diff --git a/.csslintrc b/.csslintrc new file mode 100644 index 000000000..d1dac24ba --- /dev/null +++ b/.csslintrc @@ -0,0 +1,38 @@ +/* https://github.com/CSSLint/csslint/wiki/Rules */ +{ + "important": false, + "adjoining-classes": false, + "known-properties": false, + "box-sizing": false, + "box-model": false, + "overqualified-elements": false, + "display-property-grouping": false, + "bulletproof-font-face": false, + "compatible-vendor-prefixes": false, + "regex-selectors": false, + "errors": true, + "duplicate-background-images": false, + "duplicate-properties": false, + "empty-rules": false, + "selector-max-approaching": false, + "gradients": false, + "fallback-colors": false, + "font-sizes": false, + "font-faces": false, + "floats": false, + "star-property-hack": false, + "outline-none": false, + "import": false, + "ids": false, + "underscore-property-hack": false, + "rules-count": false, + "qualified-headings": false, + "selector-max": false, + "shorthand": false, + "text-indent": false, + "unique-headings": false, + "universal-selector": false, + "unqualified-attributes": false, + "vendor-prefix": false, + "zero-units": false +} \ No newline at end of file diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 000000000..c5271f002 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,246 @@ +/* https://github.com/eslint/eslint/tree/master/docs/rules */ +{ + "rules": { + + /* + Possible Errors + The follow rules point out areas where you + might have made mistakes. + */ + "comma-dangle": [2, "never"], + "no-cond-assign": 2, + "no-console": 2, + "no-constant-condition": 2, + "no-control-regex": 2, + "no-debugger": 1, + "no-dupe-args": 2, + "no-dupe-keys": 2, + "no-duplicate-case": 2, + "no-empty-character-class": 2, + "no-empty": 2, + "no-ex-assign": 2, + "no-extra-boolean-cast": 2, + "no-extra-semi": 2, + "no-func-assign": 2, + "no-inner-declarations": 2, + "no-invalid-regexp": 2, + "no-irregular-whitespace": 2, + "no-negated-in-lhs": 2, + "no-obj-calls": 2, + "no-regex-spaces": 2, + "no-sparse-arrays": 2, + "no-unexpected-multiline": 2, + "no-unreachable": 2, + "use-isnan": 2, + "valid-jsdoc": 2, + "valid-typeof": 2, + + // ignored possible errors + "no-extra-parens": 0, + + + /* + Best Practices + These are rules designed to prevent you from making + mistakes. They either prescribe a better way of + doing something or help you avoid footguns. + */ + "accessor-pairs": [2, { + "getWithoutSet": true + }], + "block-scoped-var": 2, + "complexity": [2, 20], /** TODO should try to get this lower **/ + "consistent-return": 2, + "curly": 2, + "default-case": 2, + "dot-location": [2, "property"], + "dot-notation": 2, + "eqeqeq": 2, + "guard-for-in": 2, + "max-statements": [1, 30, {"ignoreTopLevelFunctions": true}], + "no-alert": 2, + "no-caller": 2, + "no-div-regex": 2, + "no-empty-pattern": 2, + "no-eq-null": 2, + "no-eval": 2, + "no-extend-native": 2, + "no-extra-bind": 2, + "no-fallthrough": 2, + "no-floating-decimal": 2, + "no-implicit-coercion": 2, + "no-implied-eval": 2, + "no-iterator": 2, + "no-labels": 2, + "no-lone-blocks": 2, + "no-loop-func": 2, + "no-multi-spaces": 2, + "no-multi-str": 2, + "no-native-reassign": 2, + "no-new-func": 2, + "no-new-wrappers": 2, + "no-new": 2, + "no-octal-escape": 2, + "no-octal": 2, + "no-process-env": 2, + "no-proto": 2, + "no-redeclare": 2, + "no-return-assign": 2, + "no-script-url": 2, + "no-self-compare": 2, + "no-sequences": 2, + "no-throw-literal": 2, + "no-unused-expressions": 2, + "no-useless-call": 2, + "no-useless-concat": 2, + "no-void": 2, + "no-with": 2, + "radix": 2, + "wrap-iife": [2, "inside"], + "yoda": 2, + + // ignored best practices rules + "no-else-return": 0, + "no-invalid-this": 0, + "no-magic-numbers": 0, + "no-param-reassign": 0, + "no-warning-comments": 0, + "vars-on-top": 0, + + + /* + Strict Mode + */ + "strict": 2, + + + /* + Variables + These rules have to do with variable declarations. + */ + "no-catch-shadow": 2, + "no-delete-var": 2, + "no-label-var": 2, + "no-shadow-restricted-names": 2, + "no-shadow": 2, + "no-undef-init": 2, + "no-undef": 2, + "no-unused-vars": 2, + "no-use-before-define": 2, + + // ignore variable rules + "init-declarations": 0, + "no-undefined": 0, + + + /* + Stylistic Issues + These rules are purely matters of style and + are quite subjective. + */ + "array-bracket-spacing": [2, "never"], + "block-spacing": [2, "always"], + "brace-style": [2, "1tbs", { + "allowSingleLine": false + }], + "camelcase": 2, + "comma-spacing": [2, { + "before": false, + "after": true + }], + "comma-style": 2, + "computed-property-spacing": [2, "never"], + "consistent-this": [2, "self"], + "func-style": [2, "declaration"], + "indent": [2, 4], + "key-spacing": [2, { + "beforeColon": false, + "afterColon": true, + "mode": "strict" + }], + "keyword-spacing": [2, {"before": true, "after": true, "overrides": {}}], + "max-nested-callbacks": [2, 4], + "new-cap": 2, + "new-parens": 2, + "no-array-constructor": 2, + "no-continue": 2, + "no-lonely-if": 2, + "no-mixed-spaces-and-tabs": 2, + "no-multiple-empty-lines": 2, + "object-curly-spacing": [2, "never"], + "operator-assignment": 2, + "operator-linebreak": 2, + "quotes": [2, "single"], + "semi-spacing": [2, { + "before": false, + "after": true + }], + "semi": [2, "always"], + "space-before-blocks": [2, "always"], + "space-before-function-paren": [2, "always"], + "space-in-parens": [2, "never"], + "space-infix-ops": 2, + "wrap-regex": 2, + + // ignored stylistic rules + "eol-last": 0, + "func-names": 0, + "id-match": 0, + "jsx-quotes": 0, + "lines-around-comment": 0, + "linebreak-style": 0, + "newline-after-var": 0, + "no-inline-comments": 0, + "no-negated-condition": 0, + "no-underscore-dangle": 0, + "one-var": 0, + "padded-blocks": 0, + "quote-props": 0, + "require-jsdoc": 0, + "space-unary-ops": 0, + "spaced-comment": 0, + + + /* + ECMAScript 6 + These rules are only relevant to ES6 environments. + */ + "arrow-parens": [2, "always"], + "arrow-spacing": [2, { + "before": true, + "after": true + }], + "constructor-super": 2, + "generator-star-spacing": [2, { + "before": true, + "after": true + }], + "no-class-assign": 2, + "no-const-assign": 2, + "no-dupe-class-members": 2, + "no-this-before-super": 2, + "prefer-const": 2, + "prefer-spread": 2, + "require-yield": 2, + + // ignored ECMA6 rules + "no-arrow-condition": 0, + "no-var": 0, + "object-shorthand": 0, + "prefer-arrow-callback": 0, + "prefer-reflect": 0, + "prefer-template": 0 + + }, + "env": { + "amd": true, + "es6": true, + "browser": true + }, + "globals": { + "define": true, + "require": true + }, + "parser": "babel-eslint", + "extends": "eslint:recommended" +} \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..413eaa59d --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,49 @@ + + +__How often can you reproduce it?__ + +- [ ] Always +- [ ] Sometimes +- [ ] Rarely +- [ ] Unable +- [ ] I didn’t try + + + +__Description:__ + + + + + +__Steps to reproduce:__ + +1. Include a JS Bin (or equivalent) link if possible. [You can use this as a starting point](http://jsbin.com/guresequba/edit?js,output) +2. Detail the exact steps taken to produce the problem +3. Include a gif if possible; you can use LICEcap to make a gif: http://www.cockos.com/licecap/ +4. Check the browser console for errors (Use F12 to access the console) + + + +__Expected results:__ + + + + + +__Actual results:__ + + + + + +__Environment:__ + +| Software | Version +| ------------------ | ------- +| CMV Version | +| Browser | +| Operating system | diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..3fd7ca439 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,18 @@ + + +# Description + + +# Use case + +```javascript +// how the code can be used +``` + +# Checklist + + + - [ ] `grunt lint` produces no error messages diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 248185ccb..000000000 --- a/.jshintrc +++ /dev/null @@ -1,102 +0,0 @@ -{ - // JSHint Configuration, esri jsapi - // Modified from [jshint web defaults][1]. - // Differences between the default and our file are noted - // Options that are commented out completely are uneccesary or problematic for our codebase - // [1] : https://github.com/jshint/jshint/blob/2.x/examples/.jshintrc - // See http://jshint.com/docs/ for more details - - "maxerr" : 5000, // {int} Maximum error before stopping ** Get ALL the errors ** - - // Enforcing - true = enforce this rule, false = don't enforce this rule - "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.) - "camelcase" : false, // true: Identifiers must be in camelCase - "curly" : true, // true: Require {} for every new block or scope - "eqeqeq" : false, // true: Require triple equals (===) for comparison ** Just use triples with undefined, null, false, 0 and 1 ** - "es3" : true, // true: Adhere to ECMAScript 3 specification ** Still needed until IE8 support is dropped ** - "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty() ** Still needed until IE8 support is dropped ** - "immed" : true, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());` ** Avoids confusion and minification errors ** - "latedef" : false, // true: Require variables/functions to be defined before being used - "newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()` ** Coding style enforcement ** - "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` - "noempty" : true, // true: Prohibit use of empty blocks - "nonew" : true, // true: Prohibit use of constructors for side-effects (without assignment) ** Coding style enforcement ** - "plusplus" : false, // true: Prohibit use of `++` & `--` - "quotmark" : "single", // Quotation mark consistency: ** Use the same style. Doubles should be used in most cases ** - // false : do nothing (default) - // true : ensure whatever is used is consistent - // "single" : require single quotes - // "double" : require double quotes - "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks) - "unused" : "strict", // Warns when you define and never use your variables - // true : allow unused parameters that are followed by a used parameter. - // "vars" : to only check for variables, not function parameters - // "strict" : to check all variables and parameters. - "strict" : false, // true: Requires all functions run in ES5 Strict Mode ** Dojo style and existing codebase conflicts ** - "trailing" : false, // true: Prohibit trailing whitespaces - "indent" : 4, // {int} Number of spaces to use for indentation - //"maxparams" : false, // {int} Max number of formal params allowed per function - //"maxdepth" : false, // {int} Max depth of nested blocks (within functions) - //"maxstatements" : false, // {int} Max number statements per function - //"maxcomplexity" : false, // {int} Max cyclomatic complexity per function - //"maxlen" : false, // {int} Max number of characters per line - - // Relaxing - false = continue to enforce this rule, true = don't enforce this rule (relax it) - "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) - "boss" : false, // true: Tolerate assignments where comparisons would be expected - "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. - "eqnull" : true, // true: Tolerate use of `== null` - "es5" : false, // true: Allow ES5 syntax (ex: getters and setters) - "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`) - "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features) - // (ex: `for each`, multiple try/catch, function expression…) - "evil" : false, // true: Tolerate use of `eval` and `new Function()` - "expr" : false, // true: Tolerate `ExpressionStatement` as Programs - "funcscope" : true, // true: Tolerate defining variables inside control statements ** Other variable checks keep use from abusing this ** - "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict') - "iterator" : false, // true: Tolerate using the `__iterator__` property - "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block - "laxbreak" : false, // true: Tolerate possibly unsafe line breakings - "laxcomma" : false, // true: Tolerate comma-first style coding - "loopfunc" : true, // true: Tolerate functions being defined in loops ** Almost required in some callback & promise style code ** - "multistr" : false, // true: Tolerate multi-line strings - "proto" : false, // true: Tolerate using the `__proto__` property - "scripturl" : true, // true: Tolerate script-targeted URLs ** If this is being used, there is probably a good reason ** - "smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment - "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` - "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation - "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` - "validthis" : true, // true: Tolerate using this in a non-constructor function ** We don't run in `strict mode` & coding style conflicts ** - - // Environments - "browser" : true, // Web Browser (window, document, etc) - "devel" : true, // Development/debugging (alert, confirm, etc) - "couch" : false, // CouchDB - "dojo" : false, // Dojo Toolkit ** Don't use global dojo objects. Use AMD style coding ** - "jquery" : false, // jQuery - "mootools" : false, // MooTools - "node" : false, // Node.js - "nonstandard" : false, // Widely adopted globals (escape, unescape, etc) - "prototypejs" : false, // Prototype and Scriptaculous - "rhino" : false, // Rhino - "worker" : false, // Web Workers ** Make a jshint comment when this is `true` ** - "wsh" : false, // Windows Scripting Host - "yui" : false, // Yahoo User Interface - - // Legacy ** According to jshint docs, these options are NOT to be used or relied on. Removing them. - //"nomen" : false, // true: Prohibit dangling `_` in variables - //"onevar" : false, // true: Allow only one `var` statement per function - //"passfail" : false, // true: Stop on first error - //"white" : false, // true: Check against strict whitespace and indentation rules - - // Custom Globals - additional predefined global variables - // Using both `predef` and `globals` to support tools with older jshint parsers - "predef" : [ - "define", - "require" - ], - "globals" : { // ** `false` = don't allow variable to be redefined locally - "define": false, - "require": false - } -} diff --git a/.travis.yml b/.travis.yml index 1f46d5c9f..88a5a983b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: node_js node_js: -- '0.10' +- '5' +sudo: false before_install: npm install -g grunt-cli before_script: grunt build --verbose deploy: diff --git a/Gruntfile.js b/Gruntfile.js index 44ad2291d..7dd557a52 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,167 +1,187 @@ -module.exports = function(grunt) { +/* global module */ +module.exports = function (grunt) { - // middleware for grunt.connect - var middleware = function(connect, options, middlewares) { - // inject a custom middleware into the array of default middlewares for proxy page - var proxypage = require('proxypage'); - var proxyRe = /\/proxy\/proxy.ashx/i; + // middleware for grunt.connect + var middleware = function (connect, options, middlewares) { + // inject a custom middleware into the array of default middlewares for proxy page + var bodyParser = require('body-parser'); + var proxypage = require('proxypage'); + var proxyRe = /\/proxy\/proxy.ashx/i; - var enableCORS = function(req, res, next) { - res.setHeader('Access-Control-Allow-Origin', req.headers.origin); - res.setHeader('Access-Control-Allow-Credentials', true); - res.setHeader('Access-Control-Allow-Methods', 'GET,HEAD,PUT,PATCH,POST,DELETE'); - res.setHeader('Access-Control-Allow-Headers', req.headers['access-control-request-headers']); - return next(); - }; + var enableCORS = function (req, res, next) { + res.setHeader('Access-Control-Allow-Origin', req.headers.origin || '*'); + res.setHeader('Access-Control-Allow-Credentials', true); + res.setHeader('Access-Control-Allow-Methods', 'GET,HEAD,PUT,PATCH,POST,DELETE'); + res.setHeader('Access-Control-Allow-Headers', req.headers['access-control-request-headers'] || 'Origin, X-Requested-With, Content-Type, Accept'); + return next(); + }; + + var proxyMiddleware = function (req, res, next) { + if (!proxyRe.test(req.url)) { + return next(); + } + proxypage.proxy(req, res); + }; - var proxyMiddleware = function(req, res, next) { - if (!proxyRe.test(req.url)) { - return next(); - } - proxypage.proxy(req, res); + middlewares.unshift(proxyMiddleware); + middlewares.unshift(enableCORS); + middlewares.unshift(bodyParser.json()); //body parser, see https://github.com/senchalabs/connect/wiki/Connect-3.0 + middlewares.unshift(bodyParser.urlencoded({extended: true})); //body parser + return middlewares; }; - middlewares.unshift(proxyMiddleware); - middlewares.unshift(enableCORS); - middlewares.unshift(connect.json()); //body parser, see https://github.com/senchalabs/connect/wiki/Connect-3.0 - middlewares.unshift(connect.urlencoded()); //body parser - return middlewares; - }; + // grunt task config + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + tag: { + banner: '/* <%= pkg.name %>\n' + + ' * version <%= pkg.version %>\n' + + ' * Project: <%= pkg.homepage %>\n' + + ' */\n' + }, + copy: { + build: { + cwd: 'viewer', + src: ['**'], + dest: 'dist/viewer', + expand: true + } + }, + clean: { + build: { + src: ['dist'] + } + }, + postcss: { + build: { + expand: true, + cwd: 'dist/viewer', + src: ['**/*.css'], + dest: 'dist/viewer' + } + }, + cssmin: { + build: { + expand: true, + cwd: 'dist/viewer', + src: ['**/*.css'], + dest: 'dist/viewer' + } + }, - // grunt task config - grunt.initConfig({ - pkg: grunt.file.readJSON('package.json'), - tag: { - banner: '/* <%= pkg.name %>\n' + - ' * version <%= pkg.version %>\n' + - ' * Project: <%= pkg.homepage %>\n' + - ' */\n' - }, - copy: { - build: { - cwd: 'viewer', - src: ['**'], - dest: 'dist/viewer', - expand: true - } - }, - clean: { - build: { - src: ['dist'] - } - }, - autoprefixer: { - build: { - expand: true, - cwd: 'dist/viewer', - src: ['**/*.css'], - dest: 'dist/viewer' - } - }, - cssmin: { - build: { - expand: true, - cwd: 'dist/viewer', - src: ['**/*.css'], - dest: 'dist/viewer' - } - }, - jshint: { - build: { - src: ['viewer/**/*.js'], - options: { - jshintrc: '.jshintrc', - reporter: require('jshint-stylish') - } - } - }, - uglify: { - build: { - files: [{ - expand: true, - cwd: 'dist/viewer', - src: ['**/*.js', '!**/config/**'], - dest: 'dist/viewer', - ext: '.js' - }], - options: { - banner: '<%= tag.banner %>', - sourceMap: true, - sourceMapIncludeSources: true, - compress: { - drop_console: true - } - } - } - }, - watch: { - dev: { - files: ['viewer/**'], - tasks: ['jshint'] - }, - build: { - files: ['dist/viewer/**'], - tasks: ['jshint'] - } - }, - connect: { - dev: { - options: { - port: 3000, - base: 'viewer', - hostname: '*', - middleware: middleware - } - }, - build: { - options: { - port: 3001, - base: 'dist/viewer', - hostname: '*', - middleware: middleware - } - } - }, - open: { - dev_browser: { - path: 'http://localhost:3000/index.html' - }, - build_browser: { - path: 'http://localhost:3001/index.html' - } - }, - compress: { - build: { - options: { - archive: 'dist/viewer.zip' + csslint: { + strict: { + src: ['viewer/**/*.css', '!viewer/css/theme/**/*.css'] + }, + lax: { + src: ['viewer/**/*.css', '!viewer/css/theme/**/*.css'], + options: { + csslintrc: '.csslintrc' + } + } + }, + + eslint: { + build: { + src: ['viewer/**/*.js'], + options: { + eslintrc: '.eslintrc' + } + } + }, + + uglify: { + build: { + files: [{ + expand: true, + cwd: 'dist/viewer', + src: ['**/*.js', '!**/config/**'], + dest: 'dist/viewer', + ext: '.js' + }], + options: { + banner: '<%= tag.banner %>', + sourceMap: true, + sourceMapIncludeSources: true, + compress: { + 'drop_console': true + } + } + } }, - files: [{ - expand: true, - cwd: 'dist/viewer', - src: ['**', '!**/dijit.css'] - }] - } - } - }); + watch: { + dev: { + files: ['viewer/**'], + tasks: ['eslint', 'csslint'] + }, + build: { + files: ['dist/viewer/**'], + tasks: ['eshint', 'csslint'] + } + }, + connect: { + dev: { + options: { + port: 3000, + base: 'viewer', + hostname: '*', + protocol: 'https', + keepalive: true, + middleware: middleware + } + }, + build: { + options: { + port: 3001, + base: 'dist/viewer', + hostname: '*', + protocol: 'https', + keepalive: true, + middleware: middleware + } + } + }, + open: { + 'dev_browser': { + path: 'https://localhost:3000/index.html' + }, + 'build_browser': { + path: 'https://localhost:3001/index.html' + } + }, + compress: { + build: { + options: { + archive: 'dist/viewer.zip' + }, + files: [{ + expand: true, + cwd: 'dist/viewer', + src: ['**', '!**/dijit.css'] + }] + } + } + }); - // load the tasks - grunt.loadNpmTasks('grunt-contrib-copy'); - grunt.loadNpmTasks('grunt-contrib-clean'); - grunt.loadNpmTasks('grunt-autoprefixer'); - grunt.loadNpmTasks('grunt-contrib-cssmin'); - grunt.loadNpmTasks('grunt-contrib-uglify'); - grunt.loadNpmTasks('grunt-contrib-jshint'); - grunt.loadNpmTasks('grunt-contrib-watch'); - grunt.loadNpmTasks('grunt-contrib-connect'); - grunt.loadNpmTasks('grunt-newer'); - grunt.loadNpmTasks('grunt-open'); - grunt.loadNpmTasks('grunt-contrib-compress'); + // load the tasks + grunt.loadNpmTasks('grunt-contrib-copy'); + grunt.loadNpmTasks('grunt-contrib-clean'); + grunt.loadNpmTasks('grunt-postcss'); + grunt.loadNpmTasks('grunt-contrib-cssmin'); + grunt.loadNpmTasks('grunt-contrib-csslint'); + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.loadNpmTasks('grunt-eslint'); + grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-contrib-connect'); + grunt.loadNpmTasks('grunt-newer'); + grunt.loadNpmTasks('grunt-open'); + grunt.loadNpmTasks('grunt-contrib-compress'); - // define the tasks - grunt.registerTask('default', 'Watches the project for changes, automatically builds them and runs a web server and opens default browser to preview.', ['jshint', 'connect:dev', 'open:dev_browser', 'watch:dev']); - grunt.registerTask('build', 'Compiles all of the assets and copies the files to the build directory.', ['clean', 'copy', 'scripts', 'stylesheets', 'compress:build']); - grunt.registerTask('build-view', 'Compiles all of the assets and copies the files to the build directory starts a web server and opens browser to preview app.', ['clean', 'copy', 'scripts', 'stylesheets', 'compress:build', 'connect:build', 'open:build_browser', 'watch:build']); - grunt.registerTask('scripts', 'Compiles the JavaScript files.', ['jshint', 'uglify']); - grunt.registerTask('stylesheets', 'Auto prefixes css and compiles the stylesheets.', ['autoprefixer', 'cssmin']); - grunt.registerTask('hint', 'Run simple jshint.', ['jshint']); + // define the tasks + grunt.registerTask('default', 'Watches the project for changes, automatically builds them and runs a web server and opens default browser to preview.', ['eslint', 'csslint:strict', 'connect:dev', 'open:dev_browser', 'watch:dev']); + grunt.registerTask('build', 'Compiles all of the assets and copies the files to the build directory.', ['clean', 'copy', 'scripts', 'stylesheets', 'compress:build']); + grunt.registerTask('build-view', 'Compiles all of the assets and copies the files to the build directory starts a web server and opens browser to preview app.', ['clean', 'copy', 'scripts', 'stylesheets', 'compress:build', 'connect:build', 'open:build_browser', 'watch:build']); + grunt.registerTask('scripts', 'Compiles the JavaScript files.', ['eslint', 'uglify']); + grunt.registerTask('stylesheets', 'Auto prefixes css and compiles the stylesheets.', ['csslint:lax', 'postcss', 'cssmin']); + grunt.registerTask('lint', 'Run eslint and csslint.', ['eslint', 'csslint:strict']); }; \ No newline at end of file diff --git a/README.md b/README.md index 9418b3fe8..4e1417eb2 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,21 @@ -# CMV - The Configurable Map Viewer +# CMV The Configurable Map Viewer -[![Read The Docs](https://img.shields.io/badge/docs-1.3.4-brightgreen.svg?style=flat)](http://docs.cmv.io/) [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/cmv/cmv-app?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](http://travis-ci.org/cmv/cmv-app.svg?branch=master)](http://travis-ci.org/cmv/cmv-app) +[![Read The Docs](https://img.shields.io/badge/docs-2.0.0--beta.1-brightgreen.svg?style=flat)](https://docs.cmv.io/) [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/cmv/cmv-app?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://travis-ci.org/cmv/cmv-app.svg?branch=master)](https://travis-ci.org/cmv/cmv-app) [![Greenkeeper badge](https://badges.greenkeeper.io/cmv/cmv-app.svg)](https://greenkeeper.io/) ## Introduction -[CMV](http://cmv.io/) is a community-supported open source mapping framework. CMV works with the [Esri JavaScript API](http://docs.cmv.io/en/latest/developers.arcgis.com/javascript/jsapi/), [ArcGIS Server](http://www.esri.com/software/arcgis/arcgisserver), [ArcGIS Online](https://arcgis.com/) and more. +[CMV](https://cmv.io/) is a community-supported open source mapping framework. CMV works with the [Esri JavaScript API](https://developers.arcgis.com/javascript/jsapi/3/), [ArcGIS Server](https://www.esri.com/software/arcgis/arcgisserver), [ArcGIS Online](https://arcgis.com/) and more. ## Make It Your Own! -This JavaScript web app can be easily configured or used as a boilerplate/starting point for basic viewers. It also demonstrates best practices for modular design and OOP via classes in JS using dojo's great [declare](http://dojotoolkit.org/reference-guide/1.9/dojo/_base/declare.html) system. +This JavaScript web app can be easily configured or used as a boilerplate/starting point for basic viewers. It also demonstrates best practices for modular design and OOP via classes in JS using dojo's great [declare](https://dojotoolkit.org/reference-guide/1.9/dojo/_base/declare.html) system. ## Try The Demo: -[http://demo.cmv.io/viewer/](http://demo.cmv.io/viewer/) +[https://demo.cmv.io/](https://demo.cmv.io/) -![screen shot 2014-08-20 at 9 59 48 pm](https://cloud.githubusercontent.com/assets/661156/3991302/5aa2e0f2-28df-11e4-94d0-9c813937d933.png) +[![Screenshot](https://cloud.githubusercontent.com/assets/200780/23583081/e38becbc-00ee-11e7-86da-13b0bf91ad8d.png)](https://demo.cmv.io/) ## Widgets Included: -- Base Maps +- Basemaps +- Basemaps Gallery - Bookmarks - Directions - Draw @@ -27,6 +28,7 @@ This JavaScript web app can be easily configured or used as a boilerplate/starti - Identify - Layer Control (Table of Contents) - Legend +- Locale (Change the Country + Language) - Locate Button (Geolocation) - MapInfo - Measure @@ -37,15 +39,18 @@ This JavaScript web app can be easily configured or used as a boilerplate/starti - Map Right click menu with various widget functions. - Highly configurable UI, right or left sidebars with widgets in both, top and bottom regions for other content. -Read more about the [core widgets](http://docs.cmv.io/en/latest/widgets/). In addition, there is a growing number of [widgets contributed by the CMV developer community](https://github.com/cmv/cmv-contrib-widgets). +Read more about the [core widgets](https://docs.cmv.io/en/latest/widgets/). In addition, there is a growing number of [widgets contributed by the CMV developer community](https://github.com/cmv/cmv-contrib-widgets). + +## Resource Proxy: +A [resource proxy](https://github.com/Esri/resource-proxy) may be required to access some MapServices and other content that reside on a different domain. A proxy is not available for the Github demo. ## Documentation: -Use the [documentation](http://docs.cmv.io/) for getting started and guidance on configuring your application. The initial documentation is sparse. Please help make it better by contributing over at the [cmv documentation repo](https://github.com/cmv/cmv-docs). +Use the [documentation](https://docs.cmv.io/) for getting started and guidance on configuring your application. The initial documentation is sparse. Please help make it better by contributing over at the [cmv documentation repo](https://github.com/cmv/cmv-docs). -[![Read The Docs](https://img.shields.io/badge/docs-1.3.4-brightgreen.svg?style=flat)](http://docs.cmv.io/) +[![Read The Docs](https://img.shields.io/badge/docs-2.0.0--beta.1-brightgreen.svg?style=flat)](https://docs.cmv.io/) ## Community -We have a gitter.im chat room. Come on by if you have questions. The community is very helpful. [https://gitter.im/cmv/cmv-app](https://gitter.im/cmv/cmv-app) +We have a [gitter.im chat room](https://gitter.im/cmv/cmv-app). Come on by if you have questions. The community is very active and helpful. [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/cmv/cmv-app?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) @@ -60,11 +65,11 @@ There are many ways to contribute to CMV: 2. __Create documentation__ Please contribute to the [cmv documentation repo](https://github.com/cmv/cmv-docs). -3. __Answer Questions at Stack Exchange__ - [gis.stackexchange.com](https://gis.stackexchange.com/tag/cmv) is the prime destination for our Frequently Asked Questions (FAQs). Please answer questions and help new developers get more comfortable with CMV. +3. __Answer Questions at Stack Exchange__ - [gis.stackexchange.com](https://gis.stackexchange.com/tags/cmv) is the prime destination for our Frequently Asked Questions (FAQs). Please answer questions and help new developers get more comfortable with CMV. 4. __Join the Chat Room__ - Lots of us in CMV community hang out in the chat room on [Gitter](https://gitter.im/cmv/cmv-app/). Feel free to hangout with us, answer questions and throw out ideas. -5. __Submit a Pull Request__ - If you are developer and have an enhancement or bug fix you would like to submit, pull requests are welcome. Please review the [Contributing on GitHub](http://docs.cmv.io/en/latest/contribute/ContributingOnGitHub) documentation before submitting any Pull Requests. +5. __Submit a Pull Request__ - If you are developer and have an enhancement or bug fix you would like to submit, pull requests are welcome. Please review the [Contributing on GitHub](https://docs.cmv.io/en/latest/contribute/ContributingOnGitHub) documentation before submitting any Pull Requests. 6. __User contributed widgets__ - For general information on how to build a CMV widget [read the docs](https://docs.cmv.io/en/latest). Users can submit widgets to the [cmv-contrib-widgets](https://github.com/cmv/cmv-contrib-widgets) repo. These widgets are created and submitted by users. Head on over and read the details. diff --git a/package.js b/package.js new file mode 100644 index 000000000..ca310ab6a --- /dev/null +++ b/package.js @@ -0,0 +1,75 @@ +/** + * This file is referenced by the `dojoBuild` key in `package.json` and provides extra hinting specific to the Dojo + * build system about how certain files in the package need to be handled at build time. Build profiles for the + * application itself are stored in the `profiles` directory. + */ + +var profile = (function () { + //only copy files matching these expressions + //this prevents them from being evaluated as amd modules + var reCopyOnly = [ + /Gruntfile/, + /package/, + /app\.js/ + ]; + //exclude from builds completely + var reMiniExclude = [ + /Gruntfile/, + /package/ + ]; + //non-amd modules + var reNonAmd = [ + /plugins\/Google/ + ]; + return { + // Resource tags are functions that provide hints to the build system about the way files should be processed. + // Each of these functions is called once for every file in the package directory. The first argument passed to + // the function is the filename of the file, and the second argument is the computed AMD module ID of the file. + resourceTags: { + // Files that contain test code and should be excluded when the `copyTests` build flag exists and is `false`. + // It is strongly recommended that the `mini` build flag be used instead of `copyTests`. Therefore, no files + // are marked with the `test` tag here. + test: function (filename, mid) { + return false; + }, + + // Files that should be copied as-is without being modified by the build system. + // All files in the `app/resources` directory that are not CSS files are marked as copy-only, since these files + // are typically binaries (images, etc.) and may be corrupted by the build system if it attempts to process + // them and naively assumes they are scripts. + copyOnly: function (filename, mid) { + for (var i = 0; i < reCopyOnly.length; i++) { + if (reCopyOnly[i].test(filename)) { + return true; + } + } + return (/\/(images)\//.test(mid) && !/\.css$/.test(filename)) || + /\/node_modules\//.test(mid); + }, + + // Files that are AMD modules. + // All JavaScript in this package should be AMD modules if you are starting a new project. If you are copying + // any legacy scripts from an existing project, those legacy scripts should not be given the `amd` tag. + amd: function (filename, mid) { + for (var i = 0; i < reNonAmd.length; i++) { + if (reNonAmd[i].test(filename)) { + return false; + } + } + return !this.copyOnly(filename, mid) && /\.js$/.test(filename); + }, + + // Files that should not be copied when the `mini` build flag is set to true. + // In this case, we are excluding this package configuration file which is not necessary in a built copy of + // the application. + miniExclude: function (filename, mid) { + for (var i = 0; i < reMiniExclude.length; i++) { + if (reMiniExclude[i].test(filename)) { + return true; + } + } + return false; + } + } + }; +})(); diff --git a/package.json b/package.json index 86287a665..a83a5b61f 100644 --- a/package.json +++ b/package.json @@ -1,26 +1,31 @@ { - "name": "ConfigurableMapViewerCMV", - "version": "1.3.4", - "author": "cmv.io - https://github.com/cmv/", - "license": "MIT", - "year": "2015", - "homepage": "http://cmv.io/", - "repository": "https://github.com/cmv/cmv-app/", - "dependencies": { - "grunt": "0.4.x", - "grunt-autoprefixer": "0.7.x", - "grunt-contrib-clean": "0.5.x", - "grunt-contrib-connect": "0.7.x", - "grunt-contrib-copy": "0.5.x", - "grunt-contrib-cssmin": "0.9.x", - "grunt-contrib-jshint": "0.10.x", - "jshint-stylish": "0.2.x", - "grunt-contrib-uglify": "0.4.x", - "grunt-contrib-watch": "0.6.x", - "grunt-newer": "0.7.x", - "grunt-open": "0.2.x", - "grunt-contrib-compress": "0.10.x", - "proxypage": "*" - }, - "engine": "node >= 0.10" -} \ No newline at end of file + "name": "ConfigurableMapViewerCMV", + "version": "2.0.0-beta.1", + "author": "cmv.io - https://github.com/cmv/", + "license": "MIT", + "year": "2017", + "homepage": "https://cmv.io/", + "repository": "https://github.com/cmv/cmv-app/", + "dependencies": { + "babel-eslint": "~7.1.1", + "csslint": "1.0.x", + "eslint": "~3.17.0", + "grunt": "1.0.x", + "grunt-contrib-clean": "1.0.x", + "grunt-contrib-compress": "~1.4.1", + "grunt-contrib-connect": "1.0.x", + "grunt-contrib-copy": "1.0.x", + "grunt-contrib-csslint": "~2.0.x", + "grunt-contrib-cssmin": "~2.0.0", + "grunt-contrib-uglify": "~2.2.0", + "grunt-contrib-watch": "1.0.x", + "grunt-eslint": "19.0.x", + "grunt-newer": "1.2.x", + "grunt-open": "0.2.x", + "grunt-postcss": "0.8.x", + "body-parser": "~1.17.0", + "proxypage": "*" + }, + "engine": "node >= 4", + "dojoBuild": "package.js" +} diff --git a/resource-proxy.zip b/resource-proxy.zip deleted file mode 100644 index 4e1279876..000000000 Binary files a/resource-proxy.zip and /dev/null differ diff --git a/viewer/css/cmv-theme-overrides.css b/viewer/css/cmv-theme-overrides.css new file mode 100644 index 000000000..55219bc4a --- /dev/null +++ b/viewer/css/cmv-theme-overrides.css @@ -0,0 +1,286 @@ +.cmv .dijitToolbar .dijitButtonContents { + padding: 1px !important; +} + +.cmv .dijitTitlePane { + margin-bottom: 2px; + background-color: #FFF; +} + +.cmv .dijitTitlePaneTitle { + color: #666; + background-color: #F5F5F5; +} + +.cmv .dijitTitlePaneTitleOpen { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +.cmv label { + font-weight: bold; +} + +.cmv :focus { + outline: none !important; +} + +/* icons for the sidebar */ +.cmv .dijitTitlePane .dijitTitlePaneTitle .titlePaneIcon { + margin: 0 0 0 8px; + padding-top: 2px; +} +/* end custom icons */ + +/* esri popup window overrides */ + +.cmv .esriPopup .sizer { + width: 325px; +} + +.cmv .esriPopup .esriPopupWrapper { + background-color: #FFFFFF; +} +.cmv .esriPopup .attachmentsSection div { + font-weight: bold; +} +.cmv .esriPopup .contentPane table.attrTable { + width: 100%; + border-collapse: collapse; +} +.cmv .esriPopup .contentPane table.attrTable td { + padding: 2px; +} +.cmv .esriPopup .contentPane table.attrTable td.attrName { + text-align: right; + font-weight: bold; + color: #333333; + width: 40%; + padding-right: 5px; +} +.cmv .esriPopup .contentPane table.attrTable td.attrValue { + width: 60%; +} +.cmv .esriPopup .contentPane table.attrTable tr { + vertical-align: top; + border-bottom: 1px solid rgb(221, 221, 221); +} +.cmv .esriPopup .contentPane table.attrTable tr:nth-child(odd) { + background-color: none; +} +.cmv .esriPopup .contentPane table.attrTable tr:nth-child(even) { + background-color: rgb(238, 238, 238); +} + +/* end esri popup window overrides */ + +/* esri mobile popup overrides */ + +.cmv .esriPopupMobile { + z-index: 999; +} +.cmv .esriMobileNavigationBar { + background-color: #666666; + background: url("../images/linen.jpg") repeat-x scroll left top transparent; + color: #FFFFFF; +} +.cmv .esriPopupMobile .titlePane { + background-color: #666666; + background: url("../images/linen.jpg") repeat-x scroll left top transparent; + color: #FFFFFF; +} +.cmv .esriPopupMobile .pointer.bottom{ + background:url("../images/pointertop.png"); + -webkit-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -o-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); +} +.cmv .esriPopupMobile .pointer.top { + background:url("../images/pointertop.png"); +} + +/* end esri mobile popup overrides */ + +/* esri directions widget overrides */ +.cmv .simpleDirections .esriStopsGetDirections, +.cmv .simpleDirections .esriResultsPrint, +.simpleDirections .esriActivateButton { + background-color: #E6E6E6; + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(1, #e6e6e6)); + background-image: -webkit-linear-gradient(top, #fff 0%, #e6e6e6 100%); + background-image: -moz-linear-gradient(top, #fff 0%, #e6e6e6 100%); + background-image: -o-linear-gradient(top, #fff 0%, #e6e6e6 100%); + background-image: -ms-linear-gradient(top, #fff 0%, #e6e6e6 100%); + background-image: linear-gradient(top, #fff 0%, #e6e6e6 100%); + background-repeat: repeat-x; + border: 1px solid #BBB; + border-bottom: 1px solid #A8A8A8; + padding: 0px 12px; + color: #000; + letter-spacing: 0; + text-transform: none; +} +.cmv .simpleDirections .esriStopsGetDirections:before { + content: '\f277'; + font-family: 'FontAwesome'; + margin-right: 8px; +} + +.cmv .simpleDirections .esriResultsPrint { + padding: 8px; +} + +.cmv .simpleDirections .esriResultsPrint:before { + content: '\f02f'; + font-family: 'FontAwesome'; + font-size: 14px; +} + +.cmv .simpleDirections .esriActivateButton { + padding: 8px; +} + +.cmv .simpleDirections .esriActivateButton:before { + content: '\f041'; + font-family: 'FontAwesome'; + font-size: 14px; +} + +.cmv .esriDirectionsPressedButton { + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(1, #e6e6e6)); + background-image: -webkit-linear-gradient(bottom, #fff 0%, #e6e6e6 100%); + background-image: -moz-linear-gradient(bottom, #fff 0%, #e6e6e6 100%); + background-image: -o-linear-gradient(bottom, #fff 0%, #e6e6e6 100%); + background-image: -ms-linear-gradient(bottom, #fff 0%, #e6e6e6 100%); + background-image: linear-gradient(bottom, #fff 0%, #e6e6e6 100%); + background-repeat: repeat-x; + box-shadow: inset 0 2px 4px rgba(0,0,0,0.4), 0 1px 1px rgba(0,0,0,0.2); + border-top-color: #444; + border-color: #666; + -webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,0.4), 0 1px 1px rgba(0,0,0,0.2); +} + +.cmv .simpleDirections .esriLinkButton { + color: #000; + letter-spacing: 0; + text-transform: none; +} +/* end esri directions widget overrides */ + +/* flat theme */ +/* makes the flat theme more like dbootstrap */ +.flat { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +.flat a, +.flat a:hover { + text-decoration: none; +} + +.flat .dijitTitlePane { + border-color: #E0E0E0; +} + +.flat .dijitTabContainerTop-tabs .dijitTabChecked:before { + height: 3px; + background-color: #666; + top: -1px; + left: -1px; + right: -1px; +} + +.flat .dijitTitlePaneTitle { + border: 1px solid #DDD; + -webkit-border-radius: 4px; + border-radius: 4px; + padding: 8px 15px; +} + +.flat .dijitDialogTitleBar { + background-color: #F5F5F5; + color: #666; +} + +.flat .dijitTitlePaneContentOuter { + border: 1px solid #DDD; + border-top: none; +} + +.flat .dijitButtonHover .dijitButtonNode, +.flat .dijitDropDownButtonHover .dijitButtonNode, +.flat .dijitComboButton .dijitButtonNodeHover, +.flat .dijitComboButton .dijitDownArrowButtonHover, +.flat .dijitToggleButtonHover .dijitButtonNode, +.flat .dijitDropDownButtonActive .dijitButtonNode { + background-position: 0 -15px; + text-decoration: none; + transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + -webkit-transition: background-position 0.1s linear; +} +.flat .dijitButtonActive .dijitButtonNode, +.flat .dijitComboButton .dijitButtonNodeActive, +.flat .dijitToggleButtonActive .dijitButtonNode, +.flat .dijitToggleButtonChecked .dijitButtonNode, +.flat .dijitComboButton .dijitArrowButton.dijitHasDropDownOpen { + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(1, #e6e6e6)); + background-image: -webkit-linear-gradient(bottom, #fff 0%, #e6e6e6 100%); + background-image: -moz-linear-gradient(bottom, #fff 0%, #e6e6e6 100%); + background-image: -o-linear-gradient(bottom, #fff 0%, #e6e6e6 100%); + background-image: -ms-linear-gradient(bottom, #fff 0%, #e6e6e6 100%); + background-image: linear-gradient(bottom, #fff 0%, #e6e6e6 100%); + background-repeat: repeat-x; + box-shadow: inset 0 2px 4px rgba(0,0,0,0.4), 0 1px 1px rgba(0,0,0,0.2); + border-top-color: #444; + border-color: #666; + -webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,0.4), 0 1px 1px rgba(0,0,0,0.2); +} +.flat .dijitButtonDisabled .dijitButtonNode, +.flat .dijitDropDownButtonDisabled .dijitButtonNode, +.flat .dijitComboButtonDisabled .dijitButtonNode, +.flat .dijitToggleButtonDisabled .dijitButtonNode, +.flat .dijitComboBoxDisabled .dijitButtonNode, +.flat .dijitSpinnerDisabled .dijitButtonNode, +.flat .dijitSelectDisabled .dijitButtonNode { + background-image: none; + box-shadow: none; + cursor: not-allowed; + filter: alpha(opacity=65); + opacity: 0.65; + -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=65); + -webkit-box-shadow: none; +} + +.flat .success .dijitButtonNode { + background: #409843; + color: #FFF; + border-color: #39883c; +} +.flat .danger .dijitButtonNode { + background: #e32d29; + color: #FFF; + border-color: #d4201b; +} + +.flat .dijitTextBoxHover, +.flat .dijitTextBoxFocused, +.flat .dijitCheckBoxChecked, +.flat .dijitCheckBoxHover, +.flat .dijitCheckBoxCheckedHover, +.flat .dijitRadio, +.flat .dijitRadioIcon, +.flat .dijitRadioHover { + border-color: #666; +} +.flat .dijitCheckBoxChecked, +.flat .dijitRadio:after, +.flat .dijitRadioIcon:after { + background-color: #999; +} + +/* end flat theme */ diff --git a/viewer/css/main.css b/viewer/css/main.css index 8d605b40a..abf36af1f 100644 --- a/viewer/css/main.css +++ b/viewer/css/main.css @@ -4,7 +4,6 @@ body, html { margin: 0; padding: 0; overflow: hidden; - /*font-family: Tahoma;*/ font-size: 14px; } .appHeader { @@ -59,7 +58,7 @@ body, html { right: 0; border: none; padding: 0; - background-color: #FFFFFF + background-color: #FFFFFF; } #sidebarLeft { width: 334px; @@ -170,6 +169,9 @@ body, html { border-radius: 0 0 5px 5px; border-bottom: 1px solid #B5BCC7; } +.sidebarCollapseButton .open:before, .sidebarCollapseButton .close:before { + font-family: FontAwesome; +} .sidebarCollapseButtonHorz .button { padding-top: 4px; padding-left: 2px; @@ -208,113 +210,20 @@ body, html { #help_parent_underlay { display: block; } - -/* dbootstrap overrides*/ - -.dbootstrap .dijitToolbar .dijitButtonContents { - padding: 1px !important; -} -.dbootstrap .dijitTitlePane { - border: 1px solid #DDDDDD; - margin-bottom: 2px; - -webkit-border-radius: 4px; - border-radius: 4px; -} -.dbootstrap .dijitTitlePaneTitle { - color: #666666 !important; - border-bottom: none; - padding: 8px 15px; - background-color: #F5F5F5; -} -.dijitSliderBarContainerH { - z-index: 0 !important; -} -.dbootstrap .dijitTitlePaneContentInner { - background-color: #FFFFFF; -} -.dijitBorderContainerNoGutterPane { - z-index: auto; -} -.dbootstrap :focus { - outline: none !important; -} - -/* end dbootstrap overrides*/ - -/* esri popup window overrides */ - -.esriPopup .sizer { - width: 325px; -} - -.esriPopup .esriPopupWrapper { - background-color: #FFFFFF; -} -.esriPopup .attachmentsSection div { - font-weight: bold; -} -.esriPopup .contentPane table.attrTable { - width: 100%; - border-collapse: collapse; -} -.esriPopup .contentPane table.attrTable td { - padding: 2px; -} -.esriPopup .contentPane table.attrTable td.attrName { - text-align: right; - font-weight: bold; - color: #333333; - width: 40%; - padding-right: 5px; -} -.esriPopup .contentPane table.attrTable td.attrValue { - width: 60%; -} -.esriPopup .contentPane table.attrTable tr { - vertical-align: top; - border-bottom: 1px solid rgb(221, 221, 221); -} -.esriPopup .contentPane table.attrTable tr:nth-child(odd) { - background-color: none; -} -.esriPopup .contentPane table.attrTable tr:nth-child(even) { - background-color: rgb(238, 238, 238); -} - -/* end esri popup window overrides */ - -/* esri mobile popup overrides */ - -.esriPopupMobile { - z-index: 999; -} -.esriMobileNavigationBar { - background-color: #666666; - background: url("../images/linen.jpg") repeat-x scroll left top transparent; - color: #FFFFFF; -} -.esriPopupMobile .titlePane { - background-color: #666666; - background: url("../images/linen.jpg") repeat-x scroll left top transparent; - color: #FFFFFF; -} -.esriPopupMobile .pointer.bottom{ - background:url("../images/pointertop.png"); - -webkit-transform: rotate(180deg); - -moz-transform: rotate(180deg); - -o-transform: rotate(180deg); - -ms-transform: rotate(180deg); - transform: rotate(180deg); -} -.esriPopupMobile .pointer.top { - background:url("../images/pointertop.png"); +.widgetLoader { + color: #333; + display: block; + font-size: 18px; + left: 0; + margin: 4px; + text-align: center; + top: 0; + width: 100%; } -/* end esri mobile popup overrides */ - /* media queries bootstrap style - http://getbootstrap.com/css/#grid-media-queries + https://getbootstrap.com/css/#grid-media-queries */ @media screen and (max-width: 991px) { diff --git a/viewer/css/theme/flat/flat.css b/viewer/css/theme/flat/flat.css new file mode 100644 index 000000000..99e67f488 --- /dev/null +++ b/viewer/css/theme/flat/flat.css @@ -0,0 +1 @@ +.dj_ie .dijitButtonNode,.dj_ie .dijitSliderRtl .dijitRuleLabelH,.dj_ie6 .dijitTabContainerLeft-tabs .dijitTabRtl,.dj_ie6 .dijitTabContainerRight-tabs .dijitTabRtl,.dj_ie6 .dijitTabRtl .tabLabel,.dj_ie6 .dijitTitlePane .dijitTitlePaneTitle,.dj_ie6 .dijitTitlePaneContentOuter,.dj_ie7 .dijitTabContainerLeft-tabs .dijitTabRtl,.dj_ie7 .dijitTabContainerRight-tabs .dijitTabRtl{zoom:1}.dijitBorderContainer>.dijitTextArea,.dijitExpandingTextArea{resize:none}.dijitReset{margin:0;border:0;padding:0;font:inherit;color:inherit}.dj_a11y .dijitReset{-moz-appearance:none}.dijitInline{display:inline-block;#zoom:1;#display:inline;border:0;padding:0;vertical-align:middle;#vertical-align:auto}table.dijitInline{display:inline-table;box-sizing:content-box;-moz-box-sizing:content-box}.dijitHidden{display:none!important}.dijitVisible{display:block!important;position:relative}.dijitInputContainer,.dj_ie6 .dijitComboBox .dijitInputContainer{#zoom:1;overflow:hidden;float:none!important;position:relative}.dj_ie7 .dijitInputContainer{float:left!important;clear:left;display:inline-block!important}.dj_ie .dijitSelect input,.dj_ie .dijitTextBox input,.dj_ie input.dijitTextBox{font-size:100%}.dijitSelect .dijitButtonText{float:left;vertical-align:top}TABLE.dijitSelect{padding:0!important}.dijitTextBox .dijitArrowButtonContainer,.dijitTextBox .dijitSpinnerButtonContainer,.dijitValidationTextBox .dijitValidationContainer{float:right;text-align:center}.dijitSelect input.dijitInputField,.dijitTextBox input.dijitInputField{padding-left:0!important;padding-right:0!important}.dijitValidationTextBox .dijitValidationContainer{display:none}.dijitTeeny{font-size:1px;line-height:1px}.dijitOffScreen{position:absolute!important;left:50%!important;top:-10000px!important}.dijitPopup{position:absolute;background-color:transparent;margin:0;border:0;padding:0}.dijitPositionOnly{padding:0!important;border:0!important;background-color:transparent!important;background-image:none!important;height:auto!important;width:auto!important}.dijitNonPositionOnly{float:none!important;position:static!important;margin:0!important;vertical-align:middle!important}.dijitButtonNode,.dijitButtonNode *,.dijitButtonNode img,.dijitTextBox,.dj_ie .dijitToolbar .dijitComboBox{vertical-align:middle}.dijitBackgroundIframe{position:absolute;left:0;top:0;width:100%;height:100%;z-index:-1;border:0;padding:0;margin:0}.dijitDisplayNone{display:none!important}.dijitContainer{overflow:hidden}.dj_a11y .dijitCalendarIncrementControl,.dj_a11y .dijitIcon,.dj_a11y .dijitTreeExpando,.dj_a11y div.dijitArrowButtonInner,.dj_a11y img.dijitArrowButtonInner,.dj_a11y span.dijitArrowButtonInner{display:none}.dijitSpinner div.dijitArrowButtonInner{display:block}.dj_a11y .dijitA11ySideArrow{display:inline!important;cursor:pointer}.dj_a11y .dijitCalendarDateLabel{padding:1px;border:0!important}.dj_a11y .dijitCalendarSelectedDate .dijitCalendarDateLabel{border-style:solid!important;border-width:1px!important;padding:0}.dj_a11y .dijitCalendarDateTemplate{padding-bottom:.1em!important;border:0!important}.dj_a11y .dijitButtonNode{border:outset #000!important;padding:0!important}.dj_a11y .dijitArrowButton{padding:0!important}.dj_a11y .dijitButtonContents{margin:.15em}.dj_a11y .dijitTextBoxReadOnly .dijitButtonNode,.dj_a11y .dijitTextBoxReadOnly .dijitInputField{border-style:outset!important;border-width:medium!important;border-color:#999!important;color:#999!important}.dijitButtonNode,.dijitSelect{border:1px solid gray}.dijitButtonNode .dijitArrowButtonInner,.dijitSelect .dijitArrowButtonInner{background:center no-repeat;direction:ltr}.dijitLeft{background-position:left top;background-repeat:no-repeat}.dijitStretch{white-space:nowrap;background-repeat:repeat-x}.dijitRight{#display:inline;background-position:right top;background-repeat:no-repeat}.dj_gecko .dj_a11y .dijitButtonDisabled .dijitButtonNode{opacity:.5}.dijitButton,.dijitComboButton,.dijitDropDownButton,.dijitToggleButton{margin:.2em;vertical-align:middle}.dijitButtonContents{display:block}td.dijitButtonContents{display:table-cell}.dijitToolbar .dijitComboButton{border-collapse:separate}.dijitToolbar .dijitButton,.dijitToolbar .dijitComboButton,.dijitToolbar .dijitDropDownButton,.dijitToolbar .dijitToggleButton{margin:0}.dijitToolbar .dijitButtonContents{padding:1px 2px}.dj_gecko .dijitToolbar .dijitButtonNode::-moz-focus-inner{padding:0}.dijitButtonNode{margin:0;line-height:20px;#vertical-align:auto;text-align:center;white-space:nowrap}.dj_webkit .dijitSpinner .dijitSpinnerButtonContainer{line-height:inherit}.dijitTextBox .dijitButtonNode{border-width:0}.dijitButtonNode,.dijitButtonNode *,.dijitSelect,.dijitSelect *{cursor:pointer}.dj_ie .dijitButtonNode button{overflow:visible}div.dijitArrowButton{float:right}.dijitTextBox{border:1px solid #000;#overflow:hidden;width:15em}.dijitTextBoxDisabled,.dijitTextBoxReadOnly{color:gray}.dj_safari .dijitTextBoxDisabled input{color:#B0B0B0}.dj_safari textarea.dijitTextAreaDisabled{color:#333}.dj_gecko .dijitTextBoxDisabled input,.dj_gecko .dijitTextBoxReadOnly input.dijitInputField{-moz-user-input:none}.dijitPlaceHolder{color:#999;position:absolute;top:0;left:0;#filter:""}.dijitTimeTextBox{width:8em}.dijitTextBox input:focus{outline:0}.dijitTextBoxFocused{outline:-webkit-focus-ring-color 5px}.dijitSelect input,.dijitTextBox input{float:left}.dj_ie6 .dijitTextBox input,.dj_ie6 input.dijitTextBox{float:none}.dijitInputInner{border:0!important;background-color:transparent!important;width:100%!important;box-shadow:none!important;padding-left:0!important;padding-right:0!important;margin-left:0!important;margin-right:0!important}.dj_a11y .dijitTextBox input{margin:0!important}.dijitSelect input,.dijitTextBox input.dijitArrowButtonInner,.dijitValidationTextBoxError input.dijitValidationInner{text-indent:-2em!important;direction:ltr!important;text-align:left!important;#text-indent:0!important;#letter-spacing:-5em!important;#text-align:right!important}.dj_ie .dijitSelect input,.dj_ie .dijitTextBox input,.dj_ie input.dijitTextBox{overflow-y:visible;line-height:20px;height:20px}.dijitSelect .dijitSelectLabel span{line-height:100%}.dj_ie .dijitSelect .dijitSelectLabel{line-height:normal}.dijitSelect td,.dj_ie6 .dijitSelect .dijitSelectLabel,.dj_ie6 .dijitSelect .dijitValidationContainer,.dj_ie6 .dijitSelect input,.dj_ie6 .dijitTextBox input,.dj_ie6 input.dijitTextBox,.dj_ie7 .dijitSelect .dijitSelectLabel,.dj_ie8 .dijitSelect .dijitSelectLabel,.dj_iequirks .dijitSelect .dijitSelectLabel,.dj_iequirks .dijitSelect input,.dj_iequirks .dijitTextBox input.dijitArrowButtonInner,.dj_iequirks .dijitTextBox input.dijitInputInner,.dj_iequirks .dijitTextBox input.dijitSpinnerButtonInner,.dj_iequirks .dijitTextBox input.dijitValidationInner,.dj_iequirks input.dijitTextBox{line-height:100%}.dj_a11y input.dijitArrowButtonInner,.dj_a11y input.dijitValidationInner{text-indent:0!important;width:1em!important;text-align:left!important;color:#000!important}.dijitValidationTextBoxError .dijitValidationContainer{display:inline;cursor:default}.bootstrap .dijitSelect .dijitArrowButton,.dijitComboBox .dijitArrowButtonContainer,.dijitSpinner .dijitSpinnerButtonContainer{border-width:0 0 0 1px!important}.dijitToolbar .dijitComboBox .dijitArrowButtonContainer,.dj_a11y .dijitSelect .dijitArrowButtonContainer{border-width:0!important}.dijitComboBox .dijitButtonNode,.dijitSpinner .dijitSpinnerButtonContainer .dijitButtonNode,.dijitSpinnerButtonContainer .dijitButtonNode{border-width:0}.dijitComboBoxMenu{list-style-type:none}.dj_ie .dj_a11y .dijitSpinner .dijitSpinnerButtonContainer .dijitButtonNode{clear:both}.dijitTextBox .dijitSpinnerButtonContainer{width:1em;position:relative!important;overflow:hidden}.dijitSpinner .dijitSpinnerButtonInner{width:1em;visibility:hidden!important;overflow-x:hidden}.dj_a11y .dijitSpinnerButtonContainer .dijitButtonNode{border-width:0!important;border-style:solid!important}.dj_a11y .dijitSpinner .dijitArrowButtonInner,.dj_a11y .dijitSpinnerButtonContainer input,.dj_a11y .dijitTextBox .dijitSpinnerButtonContainer{width:1em!important}.dj_a11y .dijitSpinner .dijitArrowButtonInner{margin:0 auto!important}.dj_ie .dj_a11y .dijitSpinner .dijitArrowButtonInner .dijitInputField{padding-left:.3em!important;padding-right:.3em!important;margin-left:.3em!important;margin-right:.3em!important;width:1.4em!important}.dj_ie7 .dj_a11y .dijitSpinner .dijitArrowButtonInner .dijitInputField{padding-left:0!important;padding-right:0!important;width:1em!important}.dj_ie6 .dj_a11y .dijitSpinner .dijitArrowButtonInner .dijitInputField{margin-left:.1em!important;margin-right:.1em!important;width:1em!important}.dj_iequirks .dj_a11y .dijitSpinner .dijitArrowButtonInner .dijitInputField{margin-left:0!important;margin-right:0!important;width:2em!important}.dijitSpinner .dijitSpinnerButtonContainer .dijitArrowButton{padding:0;position:absolute!important;float:none;height:50%;width:100%;bottom:auto;left:0;right:auto}.dj_iequirks .dijitSpinner .dijitSpinnerButtonContainer .dijitArrowButton{width:auto}.dj_a11y .dijitSpinnerButtonContainer .dijitArrowButton{overflow:visible!important}.dijitSpinner .dijitSpinnerButtonContainer .dijitDownArrowButton{top:50%;border-top-width:1px!important}.dijitSpinner .dijitSpinnerButtonContainer .dijitUpArrowButton{#bottom:50%;top:0}.dijitSpinner .dijitArrowButtonInner{margin:auto;overflow-x:hidden}.dj_iequirks .dijitSpinner .dijitArrowButtonInner{height:auto!important}.dijitSpinner .dijitArrowButtonInner .dijitInputField{-moz-transform:scale(.5);-moz-transform-origin:center top;-webkit-transform:scale(.5);-webkit-transform-origin:center top;-o-transform:scale(.5);-o-transform-origin:center top;transform:scale(.5);transform-origin:left top;padding-top:0;padding-bottom:0;padding-left:0!important;padding-right:0!important;width:100%;visibility:hidden}.dj_ie .dijitSpinner .dijitArrowButtonInner .dijitInputField{display:none}.dijitSpinner .dijitSpinnerButtonContainer .dijitArrowButtonInner{overflow:hidden}.dj_a11y .dijitSpinner .dijitSpinnerButtonContainer .dijitArrowButton{width:100%}.dj_a11y .dijitSpinnerButtonContainer,.dj_iequirks .dj_a11y .dijitSpinner .dijitSpinnerButtonContainer .dijitArrowButton{width:1em}.dj_a11y .dijitSpinner .dijitArrowButtonInner .dijitInputField{vertical-align:top;visibility:visible}.dijitCalendarIncrementControl,.dijitCheckedMenuItemIconChar,.dijitColorPalette .dijitPaletteCell,.dijitMenuItemLabel,.dijitSliderMoveable,.dijitTab *,.dijitTitlePaneTitle *,.dijitTreeRow img{vertical-align:middle}.dijitCheckBox,.dijitCheckBoxInput,.dijitRadio{padding:0;border:0;width:20px;height:20px;background-position:center center;background-repeat:no-repeat;overflow:hidden;cursor:pointer}.dijitCheckBox input,.dijitRadio input{margin:0;padding:0;display:block}.dijitCheckBoxInput{opacity:.01}.dj_ie .dijitCheckBoxInput{filter:alpha(opacity=0)}.dj_a11y .dijitCheckBox,.dj_a11y .dijitRadio{width:auto!important;height:auto!important}.dj_a11y .dijitCheckBoxInput{opacity:1;filter:none;width:auto;height:auto}.dj_a11y .dijitFocusedLabel{border:1px dotted;outline:0!important}.dijitProgressBar{z-index:0}.dijitProgressBarEmpty{position:relative;overflow:hidden;border:1px solid #000;z-index:0}.dijitProgressBarFull,.dijitProgressBarTile{position:absolute;overflow:hidden;top:0;width:100%}.dijitProgressBarFull{z-index:-1}.dj_ie6 .dijitProgressBarFull{height:1.6em}.dijitProgressBarTile{left:0;bottom:0;right:0;margin:0;padding:0;height:auto;background-color:#aaa}.dj_a11y .dijitProgressBarTile{border-width:2px;border-style:solid;background-color:transparent!important}.dj_ie6 .dijitProgressBarTile{position:static;height:1.6em}.dijitProgressBarIndeterminateHighContrastImage{display:none}.dj_a11y .dijitProgressBarIndeterminate .dijitProgressBarIndeterminateHighContrastImage{display:block;position:absolute;top:0;bottom:0;margin:0;padding:0;width:100%;height:auto}.dijitProgressBarLabel{display:block;position:static;width:100%;text-align:center;background-color:transparent!important}.dijitTooltip,.dijitTooltipConnector{position:absolute}.dijitTooltip{z-index:2000;display:block;left:0;top:-10000px;overflow:visible}.dijitTooltipContainer{border:2px solid #000;background:#b8b5b5;color:#000;font-size:small}.dijitTooltipFocusNode{padding:2px}.dijitTooltipData,.dj_a11y .dijitTooltipConnector{display:none}.dijitLayoutContainer{position:relative;display:block;overflow:hidden}.dijitAlignBottom,.dijitAlignLeft,.dijitAlignRight,.dijitAlignTop{position:absolute;overflow:hidden}body .dijitAlignClient{position:absolute}.dijitBorderContainer,.dijitBorderContainerNoGutter{position:relative;overflow:hidden;z-index:0}.dijitBorderContainerNoGutterPane,.dijitBorderContainerPane{position:absolute!important;z-index:2}.dijitGutter{position:absolute;font-size:1px}.dijitSplitter{position:absolute;overflow:hidden;z-index:10;background-color:#fff;border-color:gray;border-style:solid;border-width:0}.dj_ie .dijitSplitter{z-index:1}.dijitSplitterActive{z-index:11!important}.dijitSplitterCover{position:absolute;z-index:-1;top:0;left:0;width:100%;height:100%}.dijitSplitterCoverActive{z-index:3!important}.dj_ie .dijitSplitterCover{background:#fff;filter:alpha(opacity=0)}.dijitSplitterH{height:7px;border-top:1px;border-bottom:1px;cursor:row-resize}.dijitSplitContainerSizerH,.dijitSplitContainerVirtualSizerH,.dijitSplitterV{cursor:col-resize}.dijitSplitterV{width:7px;border-left:1px;border-right:1px}.dijitSplitContainer{position:relative;overflow:hidden;display:block}.dijitSplitPane{position:absolute}.dijitSplitContainerSizerH,.dijitSplitContainerSizerV{position:absolute;font-size:1px;background-color:ThreeDFace;border:1px solid;border-color:ThreeDHighlight ThreeDShadow ThreeDShadow ThreeDHighlight;margin:0}.dijitSplitContainerSizerH .thumb,.dijitSplitterV .dijitSplitterThumb{overflow:hidden;position:absolute;top:49%}.dijitSplitContainerSizerV .thumb,.dijitSplitterH .dijitSplitterThumb{position:absolute;left:49%}.dijitSplitContainerVirtualSizerH,.dijitSplitContainerVirtualSizerV,.dijitSplitterShadow{font-size:1px;background-color:ThreeDShadow;-moz-opacity:.5;opacity:.5;filter:Alpha(Opacity=50);margin:0}.dijitSplitContainerSizerV,.dijitSplitContainerVirtualSizerV{cursor:row-resize}.dj_a11y .dijitSplitterH{border-top:1px solid #d3d3d3!important;border-bottom:1px solid #d3d3d3!important}.dj_a11y .dijitSplitterV{border-left:1px solid #d3d3d3!important;border-right:1px solid #d3d3d3!important}.dijitContentPane{display:block;overflow:auto}.dijitAccordionChildWrapper,.dijitContentPaneSingleChild,.dijitSpacer,.dijitTitlePane{overflow:hidden}.dijitContentPaneError .dijitIconError,.dijitContentPaneLoading .dijitIconLoading{margin-right:9px}.dijitTitlePane{display:block}.dijitFixedClosed .dijitArrowNode,.dijitFixedClosed .dijitArrowNodeInner,.dijitFixedOpen .dijitArrowNode,.dijitFixedOpen .dijitArrowNodeInner,.dijitTitlePane .dijitArrowNodeInner{display:none}.dijitTitlePaneTitle{cursor:pointer}.dijitFixedClosed,.dijitFixedOpen{cursor:default}.dj_a11y .dijitTitlePane .dijitArrowNodeInner{display:inline!important;font-family:monospace}.dijitAccordionTitle .arrowTextDown,.dijitAccordionTitle .arrowTextUp,.dj_a11y .dijitTitlePane .dijitArrowNode{display:none}.dijitColorPalette{border:1px solid #999;background:#fff;position:relative}.dijitColorPalette .dijitPaletteTable{padding:2px 3px 3px;position:relative;overflow:hidden;outline:0;border-collapse:separate}.dj_ie6 .dijitColorPalette .dijitPaletteTable,.dj_ie7 .dijitColorPalette .dijitPaletteTable,.dj_iequirks .dijitColorPalette .dijitPaletteTable{padding:0;margin:2px 3px 3px}.dijitColorPalette .dijitPaletteCell{font-size:1px;text-align:center;background:0 0}.dijitColorPalette .dijitPaletteImg{padding:1px;border:1px solid #999;margin:2px 1px;cursor:default;font-size:1px}.dj_gecko .dijitColorPalette .dijitPaletteImg{padding-bottom:0}.dijitColorPalette .dijitColorPaletteSwatch{width:14px;height:12px}.dijitPaletteTable td{padding:0}.dijitColorPalette .dijitPaletteCell:hover .dijitPaletteImg{border:1px solid #000}.dijitColorPalette .dijitPaletteCell:active .dijitPaletteImg,.dijitColorPalette .dijitPaletteTable .dijitPaletteCellSelected .dijitPaletteImg{border:2px solid #000;margin:1px 0}.dj_a11y .dijitColorPalette .dijitPaletteTable,.dj_a11y .dijitColorPalette .dijitPaletteTable *{background-color:transparent!important}.dijitAccordionContainer{border:1px solid #b7b7b7;border-top:0!important}.dijitAccordionTitle{cursor:pointer}.dijitAccordionTitleSelected{cursor:default}.dj_a11y .dijitAccordionTitle .arrowTextUp,.dj_a11y .dijitAccordionTitleSelected .arrowTextDown{display:inline}.dijitMenuExpandA11y,.dj_a11y .dijitAccordionTitleSelected .arrowTextUp{display:none}.dijitCalendarContainer{width:auto}.dijitCalendarContainer td,.dijitCalendarContainer th{padding:1px 2px 2px;vertical-align:middle}.dijitCalendarYearLabel{white-space:nowrap}.dijitCalendarNextYear{margin:0 0 0 .55em}.dijitCalendarPreviousYear{margin:0 .55em 0 0}.dijitCalendarDateTemplate,.dijitCalendarIncrementControl,.dijitCalendarMonthLabel,.dijitCalendarNextYear,.dijitCalendarPreviousYear{cursor:pointer}.dijitCalendarDisabledDate{color:gray;text-decoration:line-through;cursor:default}.dijitSpacer{position:relative;height:1px;visibility:hidden}.dijitCalendarMonthMenu .dijitCalendarMonthLabel{text-align:center}.dijitMenu{border:1px solid #000;background-color:#fff}.dijitMenuTable{border-collapse:collapse;border-width:0;background-color:#fff}.dj_webkit .dijitMenuTable td[colspan="2"]{border-right:hidden}.dijitMenuItem{text-align:left;white-space:nowrap;padding:.1em .2em;cursor:pointer}.dijitMenuItemDisabled *,.dijitStackController .dijitToggleButtonChecked *{cursor:default}.dijitMenuItem:focus{outline:0}.dijitMenuItemSelected,.dijitMenuPassive .dijitMenuItemHover{background-color:#000;color:#fff}.dijitMenuExpand,.dijitMenuItemIcon{background-repeat:no-repeat}.dj_ie .dijitMenuItemDisabled *,.dj_ie .dj_a11y .dijitMenuItemDisabled,.dj_ie .dj_a11y .dijitMenuItemDisabled *{color:gray;filter:alpha(opacity=35)}.dijitMenuItemLabel{position:relative}.dj_a11y .dijitMenuItemSelected{border:1px dotted #000!important}.dj_a11y .dijitMenuItemSelected .dijitMenuItemLabel{border-width:1px;border-style:solid}.dj_ie8 .dj_a11y .dijitMenuItemLabel{position:static}.dj_a11y .dijitMenuExpandA11y{display:inline}.dijitMenuSeparator td{border:0;padding:0}.dijitMenuSeparatorTop{height:50%;margin:3px 0 0;font-size:1px}.dijitMenuSeparatorBottom{height:50%;margin:0 0 3px;font-size:1px}.dijitCheckedMenuItemIconChar{visibility:hidden}.dijitCheckedMenuItemChecked .dijitCheckedMenuItemIconChar{visibility:visible}.dj_a11y .dijitCheckedMenuItemIconChar{display:inline!important}.dj_a11y .dijitCheckedMenuItemIcon{display:none}.dj_ie .dj_a11y .dijitMenuBar .dijitMenuItem{margin:0}.dijitTabContainer{z-index:0;overflow:visible}.dj_ie6 .dijitTabContainer{overflow:hidden}.dijitTabContainerNoLayout{width:100%}.dijitTabContainerBottom-tabs,.dijitTabContainerLeft-tabs,.dijitTabContainerRight-tabs,.dijitTabContainerTop-tabs{z-index:1;overflow:visible!important}.dijitTabController{z-index:1}.dijitTabContainerBottom-container,.dijitTabContainerLeft-container,.dijitTabContainerRight-container,.dijitTabContainerTop-container{z-index:0;overflow:hidden;border:1px solid #000}.nowrapTabStrip{width:50000px;display:block;position:relative;text-align:left;z-index:1}.dijitTabListWrapper{overflow:hidden;z-index:1}.dj_a11y .tabStripButton img{display:none}.dijitTabContainerTop-tabs{border-bottom:1px solid #000}.dijitTabContainerTop-container{border-top:0}.dijitTabContainerLeft-tabs{border-right:1px solid #000;float:left}.dijitTabContainerLeft-container{border-left:0}.dijitTabContainerBottom-tabs{border-top:1px solid #000}.dijitTabContainerBottom-container{border-bottom:0}.dijitTabContainerRight-tabs{border-left:1px solid #000;float:left}.dijitTabContainerRight-container{border-right:0}.dj_ie div.dijitTabDisabled,div.dijitTabDisabled{cursor:auto}.dijitTab{position:relative;cursor:pointer;white-space:nowrap;z-index:3}.dijitTabChecked{cursor:default}.dijitTabContainerTop-tabs .dijitTab{top:1px}.dijitTabContainerBottom-tabs .dijitTab{top:-1px}.dijitTabContainerLeft-tabs .dijitTab{left:1px}.dijitTabContainerRight-tabs .dijitTab{left:-1px}.dijitTabContainerBottom-tabs .dijitTab,.dijitTabContainerTop-tabs .dijitTab{display:inline-block;#zoom:1;#display:inline}.dijitTabButtonDisabled .tabStripButton,.dijitTabCloseText{display:none}.tabStripButton{z-index:12}.dijitTabCloseButton{margin-left:1em}.dijitTab .tabLabel{display:inline-block}.dijitNoIcon{display:none}.dj_ie6 .dijitTab .dijitNoIcon{display:inline;height:15px;width:1px}.dj_a11y .dijitTabCloseButton{background-image:none!important;width:auto!important;height:auto!important}.dj_a11y .dijitTabCloseText{display:inline}.dijitAccordionContainer-child,.dijitStackContainer-child,.dijitTabPane{border:none!important}.dijitInlineEditBoxDisplayMode{border:1px solid transparent;cursor:text}.dijitInlineEditBoxDisplayModeDisabled,.dijitTreeContent{cursor:default}.dj_a11y .dijitInlineEditBoxDisplayMode,.dj_ie6 .dijitInlineEditBoxDisplayMode{border:none}.dijitInlineEditBoxDisplayModeHover,.dj_a11y .dijitInlineEditBoxDisplayModeHover,.dj_ie6 .dijitInlineEditBoxDisplayModeHover{background-color:#e2ebf2;border:1px solid #000}.dijitTree{overflow:auto}.dijitTreeContainer{float:left}.dijitTreeIndent{width:19px}.dijitTreeContent,.dijitTreeRow{white-space:nowrap}.dj_ie .dijitTreeLabel:focus{outline:#000 dotted 1px}.dijitExpandoText{display:none}.dj_a11y .dijitExpandoText{display:inline;padding-left:10px;padding-right:10px;font-family:monospace;border-style:solid;border-width:thin;cursor:pointer}.dijitSlider .dijitButtonNode,.dijitSliderButton{padding:0;display:block}.dijitTreeLabel{margin:0 4px}.dijitDialog{position:absolute;z-index:999;overflow:hidden}.dijitDialogTitleBar{cursor:move}.dijitDialogFixed .dijitDialogTitleBar{cursor:default}.dijitDialogCloseIcon,.dijitSliderBar,.dijitSliderButtonContainer *,.dijitTimePickerItemHover{cursor:pointer}.dijitDialogPaneContent{-webkit-overflow-scrolling:touch}.dijitDialogUnderlayWrapper{position:absolute;left:0;top:0;z-index:998;display:none;background:0 0!important}.dijitDialogUnderlay{background:#eee;opacity:.5}.dj_ie .dijitDialogUnderlay{filter:alpha(opacity=50)}.dj_a11y .dijitDialog,.dj_a11y .dijitSpinnerButtonContainer{opacity:1!important;background-color:#fff!important}.dijitDialog .closeText{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;display:block;color:#000;text-shadow:0 1px 0 #FFF;position:absolute}.dj_a11y .dijitDialog .closeText{display:inline}.dijitSliderMoveable{z-index:99;position:absolute!important;display:block}.dijitSliderMoveableH{right:0}.dijitSliderMoveableV{right:50%}.dijitSliderImageHandle,.dj_a11y div.dijitSliderImageHandle{margin:0;padding:0;position:relative!important;border:8px solid gray;width:0;height:0;cursor:pointer}.dijitSliderBarContainerH,.dijitSliderBarContainerV{position:relative;z-index:1}.dj_iequirks .dj_a11y .dijitSliderImageHandle{font-size:0}.dj_ie7 .dijitSliderImageHandle{overflow:hidden}.dj_ie7 .dj_a11y .dijitSliderImageHandle{overflow:visible}.dj_a11y .dijitSliderFocused .dijitSliderImageHandle{border:4px solid #000;height:8px;width:8px}.dijitSliderImageHandleV{top:-8px;right:-50%}.dijitSliderImageHandleH{left:50%;top:-5px;vertical-align:top}.dijitSliderBar{border-style:solid;border-color:#000}.dijitSliderBarContainerV{height:100%}.dijitSliderBarH{height:4px;border-width:1px 0}.dijitSliderBarV{width:4px;border-width:0 1px}.dijitSliderProgressBar{background-color:red;z-index:1}.dijitSliderProgressBarV{position:static!important;height:0;vertical-align:top;text-align:left}.dijitSliderProgressBarH{position:absolute!important;width:0;vertical-align:middle;overflow:visible}.dijitSliderBumper,.dijitSliderRemainingBar{overflow:hidden;z-index:1}.dijitSliderRemainingBar{background-color:transparent}.dijitSliderRemainingBarV{height:100%;text-align:left}.dijitSliderRemainingBarH{width:100%!important}.dijitSliderBumperV{width:4px;height:8px;border-width:0 1px}.dijitSliderBumperH{width:8px;height:4px;border-width:1px 0}.dijitSliderBottomBumper,.dijitSliderLeftBumper{background-color:red}.dijitSliderRightBumper,.dijitSliderTopBumper{background-color:transparent}.dijitSliderDecoration{text-align:center}.dijitSliderDecorationC,.dijitSliderDecorationV{position:relative}.dijitSliderDecorationH{width:100%}.dijitSliderDecorationV{height:100%;white-space:nowrap}.dijitSliderButton{font-family:monospace;margin:0}.dj_a11y .dijitSliderButtonInner{visibility:visible!important}.dijitSliderButtonContainer{text-align:center;height:0}.dijitRuleContainer{position:relative;overflow:visible}.dijitRuleLabelContainer,.dijitRuleMark{position:absolute}.dijitRuleContainerV{height:100%;line-height:0;float:left;text-align:left}.dj_opera .dijitRuleContainerV{line-height:2%}.dj_ie .dijitRuleContainerV{line-height:normal}.dj_gecko .dijitRuleContainerV{margin:0 0 1px}.dijitRuleMark{border:1px solid #000;line-height:0;height:100%}.dijitRuleMarkH{width:0;border-top-width:0!important;border-bottom-width:0!important}.dijitRuleLabelContainerH{text-align:center;display:inline-block}.dijitRuleLabelH{position:relative;left:-50%}.dijitRuleLabelV{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.dijitRuleMarkV{height:0;border-right-width:0!important;border-left-width:0!important;width:100%;left:0}.dj_ie .dijitRuleLabelContainerV{margin-top:-.55em}.dj_a11y .dijitSliderDisabled,.dj_a11y .dijitSliderReadOnly{opacity:.6}.dj_ie .dj_a11y .dijitSliderDisabled .dijitSliderBar,.dj_ie .dj_a11y .dijitSliderReadOnly .dijitSliderBar{filter:alpha(opacity=40)}.dj_a11y .dijitSlider .dijitSliderButtonContainer div{font-family:monospace;font-size:1em;line-height:1em;height:auto;width:auto;margin:0 4px}.dj_a11y .dijitButtonContents .dijitButtonText,.dj_a11y .dijitTab .tabLabel{display:inline!important}.dj_a11y .dijitSelect .dijitButtonText{display:inline-block!important}.dijitSelectError .dijitButtonContents .dijitButtonText{display:none!important}.dijitTextArea{width:100%;overflow-y:auto}.dijitTextArea[cols],.dj_ie .dijitTextAreaCols{width:auto}.dijitToolbarSeparator{height:18px;width:5px;padding:0 1px;margin:0}.dijitIEFixedToolbar{position:absolute;top:expression(eval((document.documentElement||document.body).scrollTop))}.dijitEditor{display:block}.dijitEditorDisabled,.dijitEditorReadOnly{color:gray}.dijitTimePickerItemInner{text-align:center;border:0;padding:2px 8px}.dijitTimePicker .dijitDownArrowButton{border-top:none!important}.dijitTimePickerMarker{color:#000}.dijitTimePickerItemSelected{font-weight:700;color:#333;background-color:#b7cdee}.dijitTimePickerItemHover{background-color:gray;color:#fff}.dijitTimePickerItemDisabled{color:gray;text-decoration:line-through}.dj_a11y .dijitTimePickerItemSelected .dijitTimePickerItemInner{border:4px solid #000}.dj_a11y .dijitTimePickerItemHover .dijitTimePickerItemInner{border:4px dashed #000}.dijitToggleButtonIconChar{display:none!important}.dj_a11y .dijitToggleButton .dijitToggleButtonIconChar{display:inline!important;visibility:hidden}.dj_ie6 .dijitToggleButtonIconChar,.dj_ie6 .tabStripButton .dijitButtonText{font-family:"Arial Unicode MS"}.dojoDndAvatarHeader:before,.flat .dijitCalendarIncrementControl{font-family:flat-icon;speak:none;font-style:normal;font-variant:normal;text-transform:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.dj_a11y .dijitToggleButtonChecked .dijitToggleButtonIconChar{display:inline!important;visibility:visible!important}.dijitArrowButtonChar{display:none!important}.dj_a11y .dijitArrowButtonChar{display:inline!important}.dj_a11y .dijitComboButton .dijitArrowButtonInner,.dj_a11y .dijitDropDownButton .dijitArrowButtonInner{display:none!important}.dijitSelectMenu .dijitMenuItemIcon,.flat .dijitA11ySideArrow{display:none}.dj_a11y .dijitSelect{border-collapse:separate!important;border-width:1px;border-style:solid}.flat .dijitCalendar,.flat .dijitMenuTable,.flat table.dijitComboButton{border-collapse:separate}.dj_ie .dijitSelect{vertical-align:middle}.dj_ie6 .dijitSelect .dijitValidationContainer,.dj_ie8 .dijitSelect .dijitButtonText{vertical-align:top}.dijitSelect .dijitSelectLabel,.dijitSelectLabel *,.dj_ie6 .dijitSpinner .dijitSpinnerButtonInner,.dj_ie6 .dijitTextBox .dijitArrowButtonInner,.dj_ie6 .dijitTextBox .dijitInputContainer,.dj_iequirks .dijitTextBox .dijitInputContainer{vertical-align:baseline}.dijitNumberTextBox{text-align:left;direction:ltr}.dijitNumberTextBox .dijitInputInner{text-align:inherit}.dijitToolbar .dijitSelect{margin:0}.dj_webkit .dijitToolbar .dijitSelect{padding-left:.3em}.dijitSelect .dijitButtonContents{padding:0;white-space:nowrap;text-align:left;border-style:none solid none none;border-width:0}.dijitSelectFixedWidth .dijitButtonContents{width:100%}.dj_ie6 .dijitSelectMenu .dijitMenuItemLabel,.dj_ie7 .dijitSelectMenu .dijitMenuItemLabel{position:static}.flat .dijitCalendarYearContainer,.flat .dijitCalendarYearLabel span{vertical-align:middle}.dijitSelectSelectedOption *{font-weight:400}.dijitSelectMenu{border-width:1px}.dijitSelectMenu .dijitMenuTable{margin:0;background-color:transparent}.dijitForceStatic{position:static!important}.dijitDisabled,.dijitDisabled *,.dijitReadOnly,.dijitReadOnly *{cursor:default}.dojoDndItem{padding:2px;-webkit-touch-callout:none;-webkit-user-select:none}.dojoDndHorizontal .dojoDndItem{#display:inline;display:inline-block}.dojoDndItemAfter,.dojoDndItemBefore{border:0 solid #369}.dojoDndItemBefore{border-width:2px 0 0;padding:0 2px 2px}.dojoDndItemAfter{border-width:0 0 2px;padding:2px 2px 0}.dojoDndHorizontal .dojoDndItemBefore{border-width:0 0 0 2px;padding:2px 2px 2px 0}.dojoDndHorizontal .dojoDndItemAfter{border-width:0 2px 0 0;padding:2px 0 2px 2px}.dj_gecko .dijitArrowButtonInner INPUT,.dj_gecko INPUT.dijitArrowButtonInner{-moz-user-focus:ignore}.dijitFocused .dijitMenuItemShortcutKey{text-decoration:underline}.flat .dijitCalendar{background-color:#fff;text-align:center;padding:4px;border:1px solid #9e9e9e;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 7px 3px -4px rgba(0,0,0,.3),0 8px 8px rgba(0,0,0,.2);box-shadow:0 7px 3px -4px rgba(0,0,0,.3),0 8px 8px rgba(0,0,0,.2)}.flat .dijitCalendarMonthContainer th{text-align:center;line-height:20px;vertical-align:middle;margin:4px 0}.flat .dijitCalendarIncrementControl{font-weight:400;line-height:1;font-size:24px;border:1px solid transparent;padding:4px}.flat .dijitCalendarDecrease:before{content:"\f000"}.flat .dijitCalendarIncrease:before{content:"\f001"}.flat .dijitCalendarArrow:hover .dijitCalendarIncrementControl,.flat .dijitCalendarArrowHover .dijitCalendarIncrementControl,.flat .dijitCalendarNextYear:hover,.flat .dijitCalendarNextYearHover,.flat .dijitCalendarPreviousYear:hover,.flat .dijitCalendarPreviousYearHover{border-style:solid;border-width:1px;border-color:#9e9e9e;-webkit-border-radius:3px;border-radius:3px;line-height:20px;cursor:pointer;-webkit-transition:all 50ms linear;-moz-transition:all 50ms linear;-o-transition:all 50ms linear;-ms-transition:all 50ms linear;transition:all 50ms linear;background:#fff;padding:4px}.flat .dijitCalendarArrow:active .dijitCalendarIncrementControl,.flat .dijitCalendarArrowActive .dijitCalendarIncrementControl,.flat .dijitCalendarNextYear:active,.flat .dijitCalendarNextYearActive,.flat .dijitCalendarPreviousYear:active,.flat .dijitCalendarPreviousYearActive{-webkit-transition:none;-moz-transition:none;-o-transition:none;-ms-transition:none;transition:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.05);box-shadow:inset 0 3px 5px rgba(0,0,0,.05);background:#e0e0e0;border-color:#b3b3b3}.flat .dijitCalendarContainer td,.flat .dijitCalendarContainer th{padding:4px}.flat .dijitCalendarDayLabelTemplate{text-align:center;border-bottom:#9e9e9e}.flat .dijitCalendarDayLabel{font-weight:700;text-align:center}.flat .dijitCalendarDateTemplate{font-size:.9em;letter-spacing:.05em;text-align:center}.flat .dijitCalendarDateTemplate .dijitCalendarDateLabel{text-decoration:none;display:block;padding:2px 4px;border:0;-webkit-border-radius:50%;border-radius:50%}.flat .dijitCalendarNextMonth .dijitCalendarDateLabel,.flat .dijitCalendarPreviousMonth .dijitCalendarDateLabel{color:#c2c2c2}.flat .dijitCalendarCurrentDate .dijitCalendarDateLabel{border-color:#2196f3}.flat .dijitCalendarEnabledDate:hover .dijitCalendarDateLabel,.flat .dijitCalendarHoveredDate .dijitCalendarDateLabel{background-color:#f2f2f2}.flat .dijitCalendarActiveDate .dijitCalendarDateLabel,.flat .dijitCalendarEnabledDate:active .dijitCalendarDateLabel{background-color:#e6e6e6}.flat .dijitCalendarSelectedDate .dijitCalendarDateLabel,.flat .dijitCalendarSelectedDate.dijitCalendarHoveredDate .dijitCalendarDateLabel{color:#fff;background-color:#2196f3}.flat .dijitCalendarDisabledDate .dijitCalendarDateLabel{opacity:.65;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=65)";filter:alpha(opacity=65)}.flat .dijitCalendarYearLabel{padding:4px 0 0;margin:0;font-size:1.15em}.flat .dijitCalendarNextYear,.flat .dijitCalendarPreviousYear,.flat .dijitCalendarSelectedYear{padding:4px}.flat .dijitCalendarSelectedYear{color:#2196f3;padding:0 4px}.flat .dijitCalendarNextYear,.flat .dijitCalendarPreviousYear{color:#2196f3;font-size:.9em;line-height:20px;border:1px solid transparent}.flat .dijitCalendar .dijitDropDownButton{margin:0}.flat .dijitCalendarMonthMenu{padding:8px 0}.flat .dijitCalendarMonthMenu .dijitCalendarMonthLabel,.flat .dijitColorPalette .dijitPaletteTable{padding:4px}.flat .dijitCalendarMonthMenu .dijitCalendarMonthLabelHover{color:#fff;background-color:#2196f3}.flat .dijitColorPalette{border:1px solid #9e9e9e;background-color:#fff;-webkit-border-radius:3px;border-radius:3px}.flat .dijitColorPalette .dijitColorPaletteSwatch{height:15px;width:15px;-webkit-border-radius:2px;border-radius:2px}.flat .dijitColorPalette .dijitPaletteImg{border:1px solid transparent;line-height:normal}.flat .dijitColorPalette .dijitPaletteCell:hover .dijitPaletteImg{border-color:#9e9e9e;-webkit-box-shadow:none;box-shadow:none;-webkit-border-radius:2px;border-radius:2px;-webkit-transform:scale(1.2);-moz-transform:scale(1.2);-o-transform:scale(1.2);-ms-transform:scale(1.2);transform:scale(1.2)}.flat .dijitColorPalette .dijitPaletteCell:active .dijitPaletteImg,.flat .dijitColorPalette .dijitPaletteTable .dijitPaletteCellSelected .dijitPaletteImg{border:1px solid #2196f3;-webkit-box-shadow:0 1px .5px rgba(0,0,0,.3),0 2px 2px rgba(0,0,0,.2);box-shadow:0 1px .5px rgba(0,0,0,.3),0 2px 2px rgba(0,0,0,.2);-webkit-border-radius:2px;border-radius:2px;-webkit-transform:scale(1.2);-moz-transform:scale(1.2);-o-transform:scale(1.2);-ms-transform:scale(1.2);transform:scale(1.2)}.dojoDndAvatarItem td>*,.flat .dijitDialog{-webkit-box-shadow:0 7px 3px -4px rgba(0,0,0,.3),0 8px 8px rgba(0,0,0,.2)}.dijitPopup{-webkit-border-radius:3px;border-radius:3px}.dojoDndItem{border:1px solid transparent;cursor:pointer;-webkit-transition-duration:.25s;-moz-transition-duration:.25s;-o-transition-duration:.25s;-ms-transition-duration:.25s;transition-duration:.25s;-webkit-transition-property:background-color,border-color,opacity;-moz-transition-property:background-color,border-color,opacity;-o-transition-property:background-color,border-color,opacity;-ms-transition-property:background-color,border-color,opacity;transition-property:background-color,border-color,opacity}.dojoDndItemOver{cursor:pointer;background-color:#f5f5f5;-webkit-border-radius:3px;border-radius:3px}.dojoDndItemAnchor{background-color:transparent;border:1px dashed #2196f3;-webkit-border-radius:3px;border-radius:3px}.dojoDndItemBefore{background:0 0;padding-top:2px;border-top:1px solid #2196f3}.dojoDndItemAfter{background:0 0;padding-bottom:2px;border-bottom:1px solid #2196f3}table.dojoDndAvatar{display:block}.dojoDndAvatarHeader td{display:none}.dojoDndAvatarHeader:before{font-weight:400;line-height:1;font-size:16px;display:table-cell}.flat .dijitCheckedMenuItemIconChar,.flat .dijitDialogCloseIcon .closeText{display:none}.dojoDndCopy .dojoDndAvatarHeader:before,.dojoDndMove .dojoDndAvatarHeader:before{color:#dd2c00;content:"\f01c"}.dojoDndCopy .dojoDndAvatarCanDrop .dojoDndAvatarHeader:before,.dojoDndMove .dojoDndAvatarCanDrop .dojoDndAvatarHeader:before{color:#43a047;content:"\f008"}.dojoDndAvatarItem{-webkit-border-radius:3px;border-radius:3px}.dojoDndAvatarItem td>*{padding:4px 8px;list-style-type:none;background-color:#fff;box-shadow:0 7px 3px -4px rgba(0,0,0,.3),0 8px 8px rgba(0,0,0,.2)}.flat .dijitDialog{background-color:#fff;border:1px solid #9e9e9e;-webkit-border-radius:3px;border-radius:3px;box-shadow:0 7px 3px -4px rgba(0,0,0,.3),0 8px 8px rgba(0,0,0,.2)}.flat .dijitMenu,.flat .dijitTooltipDialog .dijitTooltipContainer{-webkit-box-shadow:0 7px 3px -4px rgba(0,0,0,.3),0 8px 8px rgba(0,0,0,.2)}.flat .dijitDialogPaneContent{background-color:#fff;-webkit-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;padding:8px;position:relative}.flat .dijitDialogPaneActionBar{padding-top:8px;text-align:right;position:relative}.flat .dijitDialogPaneActionBar .dijitButton{float:none}.flat .dijitTooltipDialog .dijitDialogPaneActionBar{-webkit-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;margin:8px 0 0}.flat .dijitDialogTitleBar{line-height:20px;border-bottom:1px solid #e0e0e0;padding:8px 12px;-webkit-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0}.flat .dijitDialogTitle{font-size:1.1em;font-weight:700}.flat .dijitDialogCloseIcon,.flat .dijitMenuExpand{font-family:flat-icon;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.flat .dijitDialogCloseIcon{width:20px;height:20px;text-align:center;position:absolute;top:8px;right:12px;line-height:1;font-size:16px;opacity:.65;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=65)";filter:alpha(opacity=65)}.flat .dijitDialogCloseIcon:before{content:"\f00e";font-size:20px}.flat .dijitDialogCloseIconActive,.flat .dijitDialogCloseIconHover{opacity:1;-ms-filter:none;filter:none}.flat .dijitDialogUnderlay{background:#000;opacity:.65;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=65)";filter:alpha(opacity=65)}.flat .dijitTooltip,.flat .dijitTooltipDialog{background:0 0}.flat .dijitTooltipContainer{background-color:#424242;opacity:1;-ms-filter:none;filter:none;padding:4px 8px;-webkit-border-radius:3px;border-radius:3px}.flat .dijitTooltip .dijitTooltipContainer{color:#fff;border:0}.flat .dijitTooltipConnector{z-index:2;width:auto;height:auto;opacity:1;-ms-filter:none;filter:none}.flat .dijitTooltipABRight .dijitTooltipConnector{left:auto!important;right:8px}.flat .dijitTooltipBelow{padding-top:4px}.flat .dijitTooltipBelow .dijitTooltipConnector{top:0;left:8px;border-bottom:4px solid #424242;border-left:4px solid transparent;border-right:4px solid transparent;border-top:0}.flat .dijitTooltipAbove{padding-bottom:4px}.flat .dijitTooltipAbove .dijitTooltipConnector{bottom:0;left:8px;border-top:4px solid #424242;border-left:4px solid transparent;border-right:4px solid transparent;border-bottom:0}.flat .dijitTooltipLeft{padding-right:4px}.flat .dijitTooltipLeft .dijitTooltipConnector{right:0;border-left:4px solid #424242;border-bottom:4px solid transparent;border-top:4px solid transparent;border-right:0}.flat .dijitTooltipRight{padding-left:4px}.flat .dijitTooltipRight .dijitTooltipConnector{left:0;border-bottom:4px solid transparent;border-top:4px solid transparent;border-right:4px solid #424242}.flat .dijitTooltipDialog .dijitTooltipContainer{background:#fff;border:1px solid #9e9e9e;-webkit-border-radius:3px;border-radius:3px;box-shadow:0 7px 3px -4px rgba(0,0,0,.3),0 8px 8px rgba(0,0,0,.2);opacity:1;-ms-filter:none;filter:none}.flat .dijitTooltipDialog.dijitTooltipBelow{padding-top:6px}.flat .dijitTooltipDialog.dijitTooltipAbove{padding-bottom:6px}.flat .dijitTooltipDialog.dijitTooltipLeft{padding-right:6px}.flat .dijitTooltipDialog.dijitTooltipRight{padding-left:6px}.flat .dijitTooltipDialog .dijitTooltipConnector{height:0;width:0;position:absolute;z-index:2;opacity:1;-ms-filter:none;filter:none}.flat .dijitTooltipDialog .dijitTooltipConnector:after{content:"";height:0;width:0;position:absolute}.flat .dijitTooltipDialog.dijitTooltipAbove .dijitTooltipConnector{border-color:#9e9e9e transparent transparent;border-width:7px 7px 0;border-style:solid}.flat .dijitTooltipDialog.dijitTooltipAbove .dijitTooltipConnector:after{border-color:#fff transparent transparent;border-width:6px 6px 0;border-style:solid;left:-6px;top:-7px}.flat .dijitTooltipDialog.dijitTooltipBelow .dijitTooltipConnector{border-color:transparent transparent #9e9e9e;border-width:0 7px 7px;border-style:solid}.flat .dijitTooltipDialog.dijitTooltipBelow .dijitTooltipConnector:after{border-color:transparent transparent #fff;border-width:0 6px 6px;border-style:solid;left:-6px;bottom:-7px}.flat .dijitTooltipDialog.dijitTooltipLeft .dijitTooltipConnector{border-color:transparent transparent transparent #9e9e9e;border-width:7px 0 7px 7px;border-style:solid}.flat .dijitTooltipDialog.dijitTooltipLeft .dijitTooltipConnector:after{border-color:transparent transparent transparent #fff;border-width:6px 0 6px 6px;border-style:solid;top:-6px;left:-7px}.flat .dijitTooltipDialog.dijitTooltipRight .dijitTooltipConnector{border-color:transparent #9e9e9e transparent transparent;border-width:7px 7px 7px 0;border-style:solid}.flat .dijitTooltipDialog.dijitTooltipRight .dijitTooltipConnector:after{border-color:transparent #fff transparent transparent;border-width:6px 6px 6px 0;border-style:solid;top:-6px;right:-7px}.flat .dijitEditor{background-color:#fff;border:1px solid #9e9e9e;-webkit-border-radius:3px;border-radius:3px}.flat .dijitEditor .dijitEditorIFrameContainer{border:1px solid transparent;border-top:1px solid #9e9e9e;padding:4px 8px;-webkit-transition:border .2s linear 0s;-moz-transition:border .2s linear 0s;-o-transition:border .2s linear 0s;-ms-transition:border .2s linear 0s;transition:border .2s linear 0s}.flat .dijitAccordionTitle,.flat .dijitTitlePaneTitle{-webkit-transition:all 50ms linear;-moz-transition:all 50ms linear;-ms-transition:all 50ms linear;cursor:pointer}.flat .dijitEditorFocused .dijitEditorIFrameContainer,.flat .dijitEditorFocused .dijitEditorIFrameContainer .dijitEditorIFrame,.flat .dijitEditorHover .dijitEditorIFrameContainer,.flat .dijitEditorHover .dijitEditorIFrameContainer .dijitEditorIFrame{border:1px solid #2196f3}.flat .dijitEditorDisabled{border:1px solid #9e9e9e;opacity:.65;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=65)";filter:alpha(opacity=65)}.flat .dijitEditorDisabled .dijitEditorIFrame,.flat .dijitEditorDisabled .dijitEditorIFrameContainer,.flat .dijitEditorDisabled .dijitEditorIFrameContainer .dijitEditorIFrame{background-color:#f5f5f5;border:1px solid transparent}.flat .dijitInlineEditBoxDisplayMode{border:1px dashed transparent;padding:4px 6px}.flat .dijitInlineEditBoxDisplayModeHover{background-color:transparent;border:1px dashed #2196f3}.flat .dijitInlineEditBoxDisplayModeDisabled{opacity:.65;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=65)";filter:alpha(opacity=65)}.flat .dijitMenu{background:#fff;border:1px solid #9e9e9e;-webkit-border-radius:3px;border-radius:3px;margin:0;box-shadow:0 7px 3px -4px rgba(0,0,0,.3),0 8px 8px rgba(0,0,0,.2)}.flat .dijitComboBoxMenu,.flat .dijitMenuTable{padding:8px 0}.flat .dijitComboBoxMenu{margin-left:0;background-image:none}.flat .dijitMenuTable{border-spacing:0 0}.flat .dijitMenuItem,.flat .dijitMenuItem td{line-height:20px;padding:8px;white-space:nowrap}.flat .dijitMenuItemActive,.flat .dijitMenuItemActive td,.flat .dijitMenuItemHover,.flat .dijitMenuItemHover td,.flat .dijitMenuItemSelected,.flat .dijitMenuItemSelected td{color:#fff;background-color:#2196f3}.flat .dijitMenuItemDisabled{color:#9e9e9e}.flat .dijitMenuItemDisabled.dijitMenuItemSelected,.flat .dijitMenuItemDisabled.dijitMenuItemSelected td{color:#f2f2f2;background:#6fbbf7}.flat .dijitMenuSeparatorTop{height:auto;margin-top:1px;border-bottom:1px solid #9e9e9e}.flat .dijitMenuSeparatorBottom{height:auto;margin-bottom:1px;border-top:1px solid transparent}.flat td.dijitMenuItemIconCell{padding:4px;margin:0 0 0 4px;text-align:center}.flat .dijitMenuExpand{line-height:1;font-size:16px}.flat .dijitMenuExpand:before{content:"\f001"}.flat .dijitMenuNextButton,.flat .dijitMenuPreviousButton{font-style:italic}.flat .dijitAccordionTitle .arrowTextDown,.flat .dijitAccordionTitle .arrowTextUp,.flat .dijitTabCloseButton,.flat .dijitTitlePane .dijitArrowNode,.flat .dijitTreeExpando{font-family:flat-icon;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.flat .dijitMenuBar{margin:0;padding:0;background-color:#f5f5f5}.flat .dijitMenuBar .dijitMenuItem{padding:8px 12px;margin:0}.flat .dijitMenuBar .dijitMenuItemActive,.flat .dijitMenuBar .dijitMenuItemActive.dijitMenuItemSelected,.flat .dijitMenuBar .dijitMenuItemHover,.flat .dijitMenuBar .dijitMenuItemHover.dijitMenuItemSelected,.flat .dijitMenuBar .dijitMenuItemSelected{color:#fff;background-color:#2196f3}.flat .dijitMenuBar .dijitMenuItemDisabled.dijitMenuItemSelected{color:#f2f2f2;background:#6fbbf7}.flat .dijitMenuPopup,.flat .dijitMenuPopup .dijitMenu{border-top-left-radius:0;border-top-right-radius:0}.flat .dijitMenuPopup .dijitMenuItem,.flat .dijitMenuPopup .dijitMenuItem td{padding:8px}.flat .dijitProgressBar{background-color:#e0e0e0;border:0;-webkit-border-radius:3px;border-radius:3px}.flat .dijitProgressBarTile{background:url(images/progressBarStrips.png) top repeat-x;-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.flat .dijitProgressBarFull{background-color:#2196f3;-webkit-transition-property:width;-moz-transition-property:width;-o-transition-property:width;-ms-transition-property:width;transition-property:width;-webkit-transition-duration:.25s;-moz-transition-duration:.25s;-o-transition-duration:.25s;-ms-transition-duration:.25s;transition-duration:.25s;height:100%}.flat .dijitProgressBar.alt-primary .dijitProgressBarFull{background-color:#1e88e5}.flat .dijitProgressBar.alt-success .dijitProgressBarFull{background-color:#43a047}.flat .dijitProgressBar.alt-info .dijitProgressBarFull{background-color:#03a9f4}.flat .dijitProgressBar.alt-warning .dijitProgressBarFull{background-color:#fb8c00}.flat .dijitProgressBar.alt-danger .dijitProgressBarFull{background-color:#e53935}.flat .dijitProgressBar.alt-inverse .dijitProgressBarFull{background-color:#616161}.flat .dijitProgressBarLabel{margin-top:.2em;margin-bottom:.2em;color:#fff;font-size:1em;text-shadow:.1em .1em 1px #424242}@-moz-keyframes progress-bar-stripes{from{background-position:75px 0}to{background-position:0 0}}@-webkit-keyframes progress-bar-stripes{from{background-position:75px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:75px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:75px 0}to{background-position:0 0}}.dijitTimePickerPopup{-webkit-box-shadow:0 7px 3px -4px rgba(0,0,0,.3),0 8px 8px rgba(0,0,0,.2);box-shadow:0 7px 3px -4px rgba(0,0,0,.3),0 8px 8px rgba(0,0,0,.2);height:200px}.dijitTimePicker{background-color:#fff;padding:4px 0;border:1px solid #9e9e9e;-webkit-border-radius:3px;border-radius:3px}.dijitTimePickerItem{margin:0}.dijitTimePickerTick{color:#9e9e9e;border:0}.dijitTimePickerMarker{background-color:transparent;white-space:nowrap;border:0}.dijitTimePickerMarkerHover,.dijitTimePickerMarkerSelected,.dijitTimePickerTickHover,.dijitTimePickerTickSelected{background:#f2f2f2;color:#424242}.dijitTimePickerMarker .dijitTimePickerItemInner,.dijitTimePickerTick .dijitTimePickerItemInner{padding:8px;margin:0}.flat .dijitTitlePaneTitle{border-style:solid;border-width:1px;border-color:#9e9e9e;padding:4px;line-height:20px;-o-transition:all 50ms linear;transition:all 50ms linear;background:#fff;-webkit-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0}.flat .dijitTitlePaneTitleHover{-webkit-transition:all .1s;-moz-transition:all .1s;-o-transition:all .1s;-ms-transition:all .1s;transition:all .1s;background:#f2f2f2;border-color:#d9d9d9}.flat .dijitTitlePaneTitleActive{-webkit-transition:none;-moz-transition:none;-o-transition:none;-ms-transition:none;transition:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.05);box-shadow:inset 0 3px 5px rgba(0,0,0,.05);background:#e0e0e0;border-color:#b3b3b3}.flat .dijitTitlePane .dijitArrowNode{line-height:1;font-size:18px;text-align:center}.flat .dijitTitlePane .dijitArrowNode:before{content:"\f007"}.flat .dijitTitlePane .dijitClosed{-webkit-border-radius:3px;border-radius:3px}.flat .dijitTitlePane .dijitClosed .dijitArrowNode:before{content:"\f006"}.flat .dijitTitlePaneContentOuter{background-color:#fff;border:1px solid #9e9e9e;border-top:none;-webkit-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px}.flat .dijitTitlePaneContentInner{padding:8px}.flat .dijitTitlePaneTextNode{margin-left:8px;margin-right:8px;vertical-align:text-top}.flat .dijitToolbar{background-color:#f5f5f5;padding:4px;zoom:1}.flat .dijitToolbar label{padding:8px}.flat .dijitToolbar .dijitButton,.flat .dijitToolbar .dijitComboButton,.flat .dijitToolbar .dijitDropDownButton,.flat .dijitToolbar .dijitToggleButton{margin-right:4px}.flat .dijitToolbar .dijitButton .dijitButtonNode,.flat .dijitToolbar .dijitComboBox .dijitButtonNode,.flat .dijitToolbar .dijitComboButton .dijitButtonNode,.flat .dijitToolbar .dijitDropDownButton .dijitButtonNode,.flat .dijitToolbar .dijitToggleButton .dijitButtonNode{border-color:transparent;padding:4px;background-color:transparent;-webkit-border-radius:3px;border-radius:3px;-webkit-transition-property:background-color;-moz-transition-property:background-color;-o-transition-property:background-color;-ms-transition-property:background-color;transition-property:background-color;-webkit-transition-duration:.3s;-moz-transition-duration:.3s;-o-transition-duration:.3s;-ms-transition-duration:.3s;transition-duration:.3s}.flat .dijitToolbar .dijitComboButton .dijitStretch{-webkit-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.flat .dijitToolbar .dijitComboButton .dijitArrowButton{-webkit-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.flat .dijitToolbar .dijitComboBox .dijitButtonNode{padding:0 8px}.flat .dijitToolbar .dijitComboBox .dijitInputInner{padding:0}.flat .dijitToolbar .dijitDropDownButton .dijitArrowButtonInner{margin-left:4px}.flat .dijitToolbar .dijitButtonHover .dijitButtonNode,.flat .dijitToolbar .dijitComboButtonHover .dijitButtonNode,.flat .dijitToolbar .dijitDropDownButtonHover .dijitButtonNode,.flat .dijitToolbar .dijitToggleButtonHover .dijitButtonNode{-webkit-transition:all .1s;-moz-transition:all .1s;-o-transition:all .1s;-ms-transition:all .1s;transition:all .1s;background:#f2f2f2;border:1px solid #9e9e9e}.flat .dijitToolbar .dijitButtonActive .dijitButtonNode,.flat .dijitToolbar .dijitDropDownButtonActive .dijitButtonNode,.flat .dijitToolbar .dijitToggleButtonActive .dijitButtonNode,.flat .dijitToolbar .dijitToggleButtonChecked .dijitButtonNode{-webkit-transition:none;-moz-transition:none;-o-transition:none;-ms-transition:none;transition:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.05);box-shadow:inset 0 3px 5px rgba(0,0,0,.05);background:#e0e0e0;border:1px solid #9e9e9e}.flat .dijitToolbarSeparator{width:1px;height:20px;background-color:#9e9e9e;padding:0;margin:0 4px}.flat .dijitDisabled .dijitToolbar{background-color:#f5f5f5;border-bottom:1px solid #9e9e9e}.flat .dijitTreeIsRoot{background-color:transparent}.flat .dijitTreeRowActive,.flat .dijitTreeRowHover{background-color:#f2f2f2;border-color:transparent}.flat .dijitTreeNode .dojoDndItemAfter,.flat .dijitTreeNode .dojoDndItemBefore,.flat .dijitTreeRow{padding:8px 0;border:0 transparent;line-height:20px;-webkit-transition-property:background-color;-moz-transition-property:background-color;-o-transition-property:background-color;-ms-transition-property:background-color;transition-property:background-color;-webkit-transition-duration:.15s;-moz-transition-duration:.15s;-o-transition-duration:.15s;-ms-transition-duration:.15s;transition-duration:.15s;-webkit-transition-timing-function:ease-out;-moz-transition-timing-function:ease-out;-o-transition-timing-function:ease-out;-ms-transition-timing-function:ease-out;transition-timing-function:ease-out}.flat .dijitTreeRowHover{-webkit-transition-duration:.15s;-moz-transition-duration:.15s;-o-transition-duration:.15s;-ms-transition-duration:.15s;transition-duration:.15s}.flat .dijitTreeRowActive.dijitTreeRowSelected,.flat .dijitTreeRowHover.dijitTreeRowSelected,.flat .dijitTreeRowSelected{color:#fff;background-color:#2196f3;border-color:transparent}.flat .dijitTreeRowActive.dijitTreeRowSelected .dijitTreeExpando,.flat .dijitTreeRowHover.dijitTreeRowSelected .dijitTreeExpando,.flat .dijitTreeRowSelected .dijitTreeExpando{color:#fff}.flat .dijitTreeExpando{font-size:16px;width:16px;height:16px;line-height:16px;text-align:center;margin-left:4px;margin-right:4px;color:#2196f3;vertical-align:middle}.flat .dijitTreeExpandoOpened:before{content:"\e60d";cursor:pointer}.flat .dijitTreeExpandoClosed:before{content:"\e60a";cursor:pointer}.flat .dijitTreeExpandoLoading:before{content:"\e60e";-webkit-animation:spinning 2s linear infinite;-moz-animation:spinning 2s linear infinite;-o-animation:spinning 2s linear infinite;-ms-animation:spinning 2s linear infinite;animation:spinning 2s linear infinite}.dj_ie8 .dijitTreeExpandoLoading:before,.dj_ie9 .dijitTreeExpandoLoading:before,.flat .dijitTab:before{content:""}.dj_ie8 .dijitTreeExpandoLoading,.dj_ie9 .dijitTreeExpandoLoading{background:url(images/loadingAnimation.gif) no-repeat}@-moz-keyframes spinning{from{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes spinning{from{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-o-keyframes spinning{from{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spinning{from{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}.flat .dijitAccordionContainer{border:0;-webkit-border-radius:3px;border-radius:3px}.flat .dijitAccordionInnerContainer{background-color:#fff;border:1px solid #9e9e9e;-webkit-transition-property:background-color,border;-moz-transition-property:background-color,border;-o-transition-property:background-color,border;-ms-transition-property:background-color,border;transition-property:background-color,border;-webkit-transition-duration:.3s;-moz-transition-duration:.3s;-o-transition-duration:.3s;-ms-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:linear;-moz-transition-timing-function:linear;-o-transition-timing-function:linear;-ms-transition-timing-function:linear;transition-timing-function:linear}.flat .dijitAccordionTitle{padding:4px;line-height:20px;-o-transition:all 50ms linear;transition:all 50ms linear;background:#fff;border:0;-webkit-border-radius:3px;border-radius:3px}.flat .dijitAccordionTitle .arrowTextDown,.flat .dijitAccordionTitle .arrowTextUp{display:none;line-height:1;text-align:center;font-size:0}.flat .dijitAccordionTitle .arrowTextDown:before,.flat .dijitAccordionTitle .arrowTextUp:before{content:"\f007";font-size:18px}.flat .dijitAccordionTitle .arrowTextUp{display:block}.flat .dijitAccordionTitle .arrowTextUp:before{content:"\f006"}.flat .dijitAccordionInnerContainerHover .dijitAccordionTitle{-webkit-transition:all .1s;-moz-transition:all .1s;-o-transition:all .1s;-ms-transition:all .1s;transition:all .1s;background:#f2f2f2;border-color:#d9d9d9}.flat .dijitAccordionInnerContainerActive .dijitAccordionTitle{-webkit-transition:none;-moz-transition:none;-o-transition:none;-ms-transition:none;transition:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.05);box-shadow:inset 0 3px 5px rgba(0,0,0,.05);background:#e0e0e0;border-color:#b3b3b3}.flat .dijitAccordionInnerContainerSelected{border:0}.flat .dijitAccordionInnerContainerSelected .dijitAccordionTitle{color:#fff;background-color:#2196f3;-webkit-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0}.flat .dijitAccordionInnerContainerSelected .dijitAccordionTitle .arrowTextUp{display:none}.flat .dijitAccordionInnerContainerSelected .dijitAccordionTitle .arrowTextDown{display:block}.flat .dijitAccordionContainer .dijitAccordionChildWrapper{background-color:#fff;border:1px solid #9e9e9e;border-top:0 none;position:relative;z-index:1;clear:both;-webkit-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px}.flat .dijitAccordionInnerContainer,.flat .dijitAccordionInnerContainer .dijitAccordionTitle,.flat .dijitAccordionInnerContainer:not(:last-child) .dijitAccordionChildWrapper{-webkit-border-radius:0;border-radius:0}.flat .dijitAccordionInnerContainer+.dijitAccordionInnerContainer{margin-top:0;position:relative;border-top:0 none}.flat .dijitAccordionInnerContainer+.dijitAccordionInnerContainerSelected:last-child .dijitAccordionTitle{-webkit-border-radius:0;border-radius:0}.flat .dijitAccordionInnerContainer:first-child,.flat .dijitAccordionInnerContainer:first-child .dijitAccordionTitle{-webkit-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0}.flat .dijitAccordionInnerContainer:last-child,.flat .dijitAccordionInnerContainer:last-child .dijitAccordionTitle{-webkit-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px}.flat .dijitBorderContainer{padding:5px}.flat .dijitBorderContainer-child,.flat .dijitSplitContainer-child{border:1px solid #9e9e9e}.flat .dijitBorderContainer-dijitAccordionContainer,.flat .dijitBorderContainer-dijitTabContainerBottom,.flat .dijitBorderContainer-dijitTabContainerLeft,.flat .dijitBorderContainer-dijitTabContainerRight,.flat .dijitBorderContainer-dijitTabContainerTop{border:none}.flat .dijitBorderContainer-dijitBorderContainer{border:0;padding:0}.flat .dijitGutterH,.flat .dijitSplitterH{background:0 0;border:0;height:5px}.flat .dijitSplitterH .dijitSplitterThumb{background:#9e9e9e;height:1px;top:2px;width:19px}.flat .dijitGutterV,.flat .dijitSplitterV{background:0 0;border:0;width:5px;margin:0}.flat .dijitSplitterV .dijitSplitterThumb{background:#9e9e9e;height:19px;left:2px;width:1px;margin:0}.flat .dijitSplitterHHover,.flat .dijitSplitterVHover{font-size:1px;background:#f2f2f2}.flat .dijitSplitterHHover .dijitSplitterThumb,.flat .dijitSplitterVHover .dijitSplitterThumb{background:#767676}.flat .dijitSplitterHActive,.flat .dijitSplitterVActive{font-size:1px;background:#f2f2f2}.flat .dijitSplitterHActive .dijitSplitterThumb,.flat .dijitSplitterVActive .dijitSplitterThumb{background:#767676}.flat .dijitContentPane{background-color:#fff;padding:8px}.flat .dijitAccordionContainer-dijitContentPane,.flat .dijitTabContainerBottom-dijitContentPane,.flat .dijitTabContainerLeft-dijitContentPane,.flat .dijitTabContainerRight-dijitContentPane,.flat .dijitTabContainerTop-dijitContentPane{background-color:#fff;padding:8px;left:0!important;top:0!important}.flat .dijitTabContainer{-webkit-border-radius:3px;border-radius:3px}.flat .dijitTabPaneWrapper{background:#fff;border:1px solid #9e9e9e;margin:0;padding:0;-webkit-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px}.flat .dijitTabContainerBottom-tabs,.flat .dijitTabContainerLeft-tabs,.flat .dijitTabContainerRight-tabs,.flat .dijitTabContainerTop-tabs{border:none}.flat .dijitTabSpacer{display:none}.flat .dijitTab{border:1px solid transparent;background-color:#fff;text-align:center;-webkit-transition-property:background,padding,margin;-moz-transition-property:background,padding,margin;-o-transition-property:background,padding,margin;-ms-transition-property:background,padding,margin;transition-property:background,padding,margin;-webkit-transition-duration:.2s;-moz-transition-duration:.2s;-o-transition-duration:.2s;-ms-transition-duration:.2s;transition-duration:.2s;-webkit-transition-timing-function:ease;-moz-transition-timing-function:ease;-o-transition-timing-function:ease;-ms-transition-timing-function:ease;transition-timing-function:ease;position:relative;z-index:0}.flat .dijitTab:before{display:block;position:absolute}.flat .dijitTabContainerTabListNested .dijitTabChecked.dijitTabActive:before,.flat .dijitTabContainerTabListNested .dijitTabChecked.dijitTabHover:before,.flat .dijitTabContainerTabListNested .dijitTabChecked:before,.flat .dijitToggleButton .dijitCheckBoxIcon{display:none}.flat .dijitTabHover{background-color:#f2f2f2}.flat .dijitTabActive{background-color:#e6e6e6}.flat .dijitTabChecked{border:1px solid #9e9e9e;z-index:1}.flat .dijitTabChecked.dijitTabActive,.flat .dijitTabChecked.dijitTabHover{border:1px solid #9e9e9e;background-color:#fff;color:#424242}.flat .dijitTabDisabled{opacity:.65;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=65)";filter:alpha(opacity=65)}.flat .dijitTabCloseButton{line-height:1;font-size:1em;vertical-align:middle;margin-left:4px;opacity:.35;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=35)";filter:alpha(opacity=35)}.flat .dijitArrowButton,.flat .dijitDropDownButton .dijitArrowButtonInner,.flat .dijitTabStripIcon{font-family:flat-icon;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;font-size:16px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.flat .dijitTabCloseButton:before{content:"\f00e"}.flat .dijitTabCloseButtonHover{opacity:.75;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=75)";filter:alpha(opacity=75)}.flat .dijitTabCloseButtonActive{opacity:1;-ms-filter:none;filter:none}.flat .dijitTabContainerTop-tabs .dijitTab{margin-right:0;padding:6px 16px;border-bottom-color:#9e9e9e;border-left:none;border-right:none}.flat .dijitTabContainerTop-tabs .dijitTabChecked{border-bottom:1px solid #fff;border-left:1px solid #9e9e9e;border-right:1px solid #9e9e9e}.flat .dijitTabContainerTop-tabs .dijitTabChecked:before{height:3px;background:#2196f3;top:-1px;left:-1px;right:-1px}.flat .dijitTabListContainer-bottom .dijitTab,.flat .dijitTabListContainer-top .dijitTab{top:0}.flat .dijitTabListContainer-top{margin-top:1px}.flat .dijitTabPaneWrapper.dijitTabContainerBottom-container{-webkit-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0}.flat .dijitTabContainerBottom-tabs .dijitTab{margin-right:0;padding:6px 16px;border-top-color:#9e9e9e;border-left:none;border-right:none}.flat .dijitTabContainerBottom-tabs .dijitTabChecked{border-top:1px solid #fff;border-left:1px solid #9e9e9e;border-right:1px solid #9e9e9e}.flat .dijitTabContainerBottom-tabs .dijitTabChecked:before{height:3px;background:#2196f3;bottom:-1px;left:-1px;right:-1px}.flat .dijitTabListContainer-bottom{margin-top:-1px}.flat .dijitTabPaneWrapper.dijitTabContainerLeft-container{-webkit-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.flat .dijitTabContainerLeft-tabs .dijitTab{margin-bottom:0;padding:8px 12px;border-right-color:#9e9e9e;border-top:none;border-bottom:none}.flat .dijitTabContainerLeft-tabs .dijitTabChecked{border-right:1px solid #fff;border-top:1px solid #9e9e9e;border-bottom:1px solid #9e9e9e}.flat .dijitTabContainerLeft-tabs .dijitTabChecked:before{width:3px;background:#2196f3;bottom:-1px;left:-1px;top:-1px}.flat .dijitTabPaneWrapper.dijitTabContainerRight-container{-webkit-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.flat .dijitTabContainerRight-tabs .dijitTab{margin-bottom:0;padding:8px 12px;border-left-color:#9e9e9e;border-top:none;border-bottom:none}.flat .dijitTabContainerRight-tabs .dijitTabChecked{border-left:1px solid #fff;border-top:1px solid #9e9e9e;border-bottom:1px solid #9e9e9e}.flat .dijitTabContainerRight-tabs .dijitTabChecked:before{width:3px;background:#2196f3;bottom:-1px;right:-1px;top:-1px}.flat .tabStripButton{background-color:#fff;border:1px solid transparent;-webkit-transition-property:background-color;-moz-transition-property:background-color;-o-transition-property:background-color;-ms-transition-property:background-color;transition-property:background-color}.flat .dijitTabListContainer-bottom .tabStripButton,.flat .dijitTabListContainer-top .tabStripButton{padding:4px 8px;margin-left:0;margin-right:0}.flat .dijitTabListContainer-top .tabStripButton{margin-bottom:1px}.flat .dijitTabListContainer-bottom .tabStripButton{margin-top:1px}.flat .tabStripButtonHover{background-color:#f2f2f2}.flat .tabStripButtonActive{background-color:#e6e6e6}.flat .dijitTabStripIcon{line-height:1;color:#2196f3;vertical-align:middle}.flat .dijitTabStripIcon:before{content:"\f004"}.flat .dijitTabStripSlideRightIcon:before{content:"\f005"}.flat .dijitTabStripMenuIcon:before{content:"\f006"}.flat .dijitTabListContainer-bottom .tabStripButtonDisabled,.flat .dijitTabListContainer-top .tabStripButtonDisabled{opacity:.65;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=65)";filter:alpha(opacity=65)}.flat .dijitTabContainerNested .dijitTabListWrapper{height:auto}.flat .dijitTabContainerTabListNested .dijitTab{color:#2196f3;margin:4px;padding:4px 8px;border:1px solid transparent;-webkit-border-radius:3px;border-radius:3px;-webkit-transition-property:background-color,border-color;-moz-transition-property:background-color,border-color;-o-transition-property:background-color,border-color;-ms-transition-property:background-color,border-color;transition-property:background-color,border-color;-webkit-transition-duration:.3s;-moz-transition-duration:.3s;-o-transition-duration:.3s;-ms-transition-duration:.3s;transition-duration:.3s}.flat .dijitTabContainerTabListNested .dijitTabHover{background-color:#f2f2f2}.flat .dijitTabContainerTabListNested .dijitTabActive{color:#2196f3;background-color:#e6e6e6}.flat .dijitTabContainerTabListNested .dijitTabChecked,.flat .dijitTabContainerTabListNested .dijitTabChecked.dijitTabActive,.flat .dijitTabContainerTabListNested .dijitTabChecked.dijitTabHover{color:#fff;background-color:#2196f3}.flat .dijitTabContainerTabListNested.dijitTabContainerBottom-tabs .dijitTab,.flat .dijitTabContainerTabListNested.dijitTabContainerTop-tabs .dijitTab{margin-right:4px}.flat .dijitTabContainerTabListNested.dijitTabContainerLeft-tabs .dijitTab,.flat .dijitTabContainerTabListNested.dijitTabContainerRight-tabs .dijitTab{margin-bottom:4px}.flat .dijitTabPaneWrapperNested{border:none;-webkit-box-shadow:none;box-shadow:none}.flat .dijitButtonText{padding:0 4px;text-align:center}.flat .dijitButton .dijitButtonNode,.flat .dijitComboButton .dijitButtonNode,.flat .dijitDropDownButton .dijitButtonNode,.flat .dijitToggleButton .dijitButtonNode{border-style:solid;border-width:1px;border-color:#9e9e9e;padding:4px;-webkit-border-radius:3px;border-radius:3px;line-height:20px;cursor:pointer;-webkit-transition:all 50ms linear;-moz-transition:all 50ms linear;-o-transition:all 50ms linear;-ms-transition:all 50ms linear;transition:all 50ms linear;background:#fff}.flat .dijitButton.alt-primary .dijitButtonNode,.flat .dijitComboBox.alt-primary .dijitButtonNode,.flat .dijitComboButton.alt-primary .dijitButtonNode,.flat .dijitDropDownButton.alt-primary .dijitButtonNode,.flat .dijitSelect.alt-primary .dijitButtonContents,.flat .dijitSelect.alt-primary .dijitButtonNode,.flat .dijitSpinner.alt-primary .dijitArrowButton,.flat .dijitToggleButton.alt-primary .dijitButtonNode{background:#1e88e5;color:#fff;border-color:#166fbd}.flat .dijitComboButton.alt-primary .dijitStretch{border-right-color:#166fbd}.flat .dijitComboButtonRtl.alt-primary .dijitStretch{border-left-color:#166fbd}.flat .dijitButton.alt-success .dijitButtonNode,.flat .dijitComboBox.alt-success .dijitButtonNode,.flat .dijitComboButton.alt-success .dijitButtonNode,.flat .dijitDropDownButton.alt-success .dijitButtonNode,.flat .dijitSelect.alt-success .dijitButtonContents,.flat .dijitSelect.alt-success .dijitButtonNode,.flat .dijitSpinner.alt-success .dijitArrowButton,.flat .dijitToggleButton.alt-success .dijitButtonNode{background:#43a047;color:#fff;border-color:#37823a}.flat .dijitComboButton.alt-success .dijitStretch{border-right-color:#37823a}.flat .dijitComboButtonRtl.alt-success .dijitStretch{border-left-color:#37823a}.flat .dijitButton.alt-info .dijitButtonNode,.flat .dijitComboBox.alt-info .dijitButtonNode,.flat .dijitComboButton.alt-info .dijitButtonNode,.flat .dijitDropDownButton.alt-info .dijitButtonNode,.flat .dijitSelect.alt-info .dijitButtonContents,.flat .dijitSelect.alt-info .dijitButtonNode,.flat .dijitSpinner.alt-info .dijitArrowButton,.flat .dijitToggleButton.alt-info .dijitButtonNode{background:#03a9f4;color:#fff;border-color:#028ac7}.flat .dijitComboButton.alt-info .dijitStretch{border-right-color:#028ac7}.flat .dijitComboButtonRtl.alt-info .dijitStretch{border-left-color:#028ac7}.flat .dijitButton.alt-warning .dijitButtonNode,.flat .dijitComboBox.alt-warning .dijitButtonNode,.flat .dijitComboButton.alt-warning .dijitButtonNode,.flat .dijitDropDownButton.alt-warning .dijitButtonNode,.flat .dijitSelect.alt-warning .dijitButtonContents,.flat .dijitSelect.alt-warning .dijitButtonNode,.flat .dijitSpinner.alt-warning .dijitArrowButton,.flat .dijitToggleButton.alt-warning .dijitButtonNode{background:#fb8c00;color:#fff;border-color:#cd7200}.flat .dijitComboButton.alt-warning .dijitStretch{border-right-color:#cd7200}.flat .dijitComboButtonRtl.alt-warning .dijitStretch{border-left-color:#cd7200}.flat .dijitButton.alt-danger .dijitButtonNode,.flat .dijitComboBox.alt-danger .dijitButtonNode,.flat .dijitComboButton.alt-danger .dijitButtonNode,.flat .dijitDropDownButton.alt-danger .dijitButtonNode,.flat .dijitSelect.alt-danger .dijitButtonContents,.flat .dijitSelect.alt-danger .dijitButtonNode,.flat .dijitSpinner.alt-danger .dijitArrowButton,.flat .dijitToggleButton.alt-danger .dijitButtonNode{background:#e53935;color:#fff;border-color:#cc1e1a}.flat .dijitComboButton.alt-danger .dijitStretch{border-right-color:#cc1e1a}.flat .dijitComboButtonRtl.alt-danger .dijitStretch{border-left-color:#cc1e1a}.flat .dijitButton.alt-inverse .dijitButtonNode,.flat .dijitComboBox.alt-inverse .dijitButtonNode,.flat .dijitComboButton.alt-inverse .dijitButtonNode,.flat .dijitDropDownButton.alt-inverse .dijitButtonNode,.flat .dijitSelect.alt-inverse .dijitButtonContents,.flat .dijitSelect.alt-inverse .dijitButtonNode,.flat .dijitSpinner.alt-inverse .dijitArrowButton,.flat .dijitToggleButton.alt-inverse .dijitButtonNode{background:#616161;color:#fff;border-color:#4f4f4f}.flat .dijitComboButton.alt-inverse .dijitStretch{border-right-color:#4f4f4f}.flat .dijitComboBoxRtlDisabled.alt-primary .dijitButtonNode,.flat .dijitComboButtonDisabled.alt-primary .dijitStretch,.flat .dijitDateTextBoxRtlDisabled.alt-primary .dijitButtonNode,.flat .dijitTimeTextBoxRtlDisabled.alt-primary .dijitButtonNode{border-right-color:#50a2eb}.flat .dijitComboButtonRtl.alt-inverse .dijitStretch{border-left-color:#4f4f4f}.flat .dijitComboBoxDisabled.alt-primary .dijitButtonNode,.flat .dijitComboButtonRtlDisabled.alt-primary .dijitStretch,.flat .dijitDateTextBoxDisabled.alt-primary .dijitButtonNode,.flat .dijitTimeTextBoxDisabled.alt-primary .dijitButtonNode{border-left-color:#50a2eb}.flat .dijitButtonHover .dijitButtonNode,.flat .dijitComboButton .dijitButtonNodeHover,.flat .dijitComboButton .dijitDownArrowButtonHover,.flat .dijitDropDownButtonHover .dijitButtonNode,.flat .dijitToggleButtonHover .dijitButtonNode{-webkit-transition:all .1s;-moz-transition:all .1s;-o-transition:all .1s;-ms-transition:all .1s;transition:all .1s;background:#f2f2f2;border-color:#d9d9d9}.flat .dijitButtonHover.alt-primary .dijitButtonNode,.flat .dijitComboBoxHover.alt-primary .dijitButtonNode,.flat .dijitComboButton.alt-primary .dijitButtonNodeHover,.flat .dijitComboButton.alt-primary .dijitDownArrowButtonHover,.flat .dijitDropDownButtonHover.alt-primary .dijitButtonNode,.flat .dijitSelect.dijitSelectOpened.alt-primary .dijitArrowButton,.flat .dijitSelect.dijitSelectOpened.alt-primary .dijitButtonContents,.flat .dijitSelectHover.alt-primary .dijitButtonContents,.flat .dijitSelectHover.alt-primary .dijitButtonNode,.flat .dijitSpinner.alt-primary .dijitDownArrowButtonHover,.flat .dijitSpinner.alt-primary .dijitUpArrowButtonHover,.flat .dijitToggleButtonHover.alt-primary .dijitButtonNode{background:#1981dd;border-color:#1774c5}.flat .dijitButtonHover.alt-success .dijitButtonNode,.flat .dijitComboBoxHover.alt-success .dijitButtonNode,.flat .dijitComboButton.alt-success .dijitButtonNodeHover,.flat .dijitComboButton.alt-success .dijitDownArrowButtonHover,.flat .dijitDropDownButtonHover.alt-success .dijitButtonNode,.flat .dijitSelect.dijitSelectOpened.alt-success .dijitArrowButton,.flat .dijitSelect.dijitSelectOpened.alt-success .dijitButtonContents,.flat .dijitSelectHover.alt-success .dijitButtonContents,.flat .dijitSelectHover.alt-success .dijitButtonNode,.flat .dijitSpinner.alt-success .dijitDownArrowButtonHover,.flat .dijitSpinner.alt-success .dijitUpArrowButtonHover,.flat .dijitToggleButtonHover.alt-success .dijitButtonNode{background:#409843;border-color:#39883c}.flat .dijitButtonHover.alt-info .dijitButtonNode,.flat .dijitComboBoxHover.alt-info .dijitButtonNode,.flat .dijitComboButton.alt-info .dijitButtonNodeHover,.flat .dijitComboButton.alt-info .dijitDownArrowButtonHover,.flat .dijitDropDownButtonHover.alt-info .dijitButtonNode,.flat .dijitSelect.dijitSelectOpened.alt-info .dijitArrowButton,.flat .dijitSelect.dijitSelectOpened.alt-info .dijitButtonContents,.flat .dijitSelectHover.alt-info .dijitButtonContents,.flat .dijitSelectHover.alt-info .dijitButtonNode,.flat .dijitSpinner.alt-info .dijitDownArrowButtonHover,.flat .dijitSpinner.alt-info .dijitUpArrowButtonHover,.flat .dijitToggleButtonHover.alt-info .dijitButtonNode{background:#03a1e8;border-color:#0390cf}.flat .dijitButtonHover.alt-warning .dijitButtonNode,.flat .dijitComboBoxHover.alt-warning .dijitButtonNode,.flat .dijitComboButton.alt-warning .dijitButtonNodeHover,.flat .dijitComboButton.alt-warning .dijitDownArrowButtonHover,.flat .dijitDropDownButtonHover.alt-warning .dijitButtonNode,.flat .dijitSelect.dijitSelectOpened.alt-warning .dijitArrowButton,.flat .dijitSelect.dijitSelectOpened.alt-warning .dijitButtonContents,.flat .dijitSelectHover.alt-warning .dijitButtonContents,.flat .dijitSelectHover.alt-warning .dijitButtonNode,.flat .dijitSpinner.alt-warning .dijitDownArrowButtonHover,.flat .dijitSpinner.alt-warning .dijitUpArrowButtonHover,.flat .dijitToggleButtonHover.alt-warning .dijitButtonNode{background:#ee8500;border-color:#d57700}.flat .dijitButtonHover.alt-danger .dijitButtonNode,.flat .dijitComboBoxHover.alt-danger .dijitButtonNode,.flat .dijitComboButton.alt-danger .dijitButtonNodeHover,.flat .dijitComboButton.alt-danger .dijitDownArrowButtonHover,.flat .dijitDropDownButtonHover.alt-danger .dijitButtonNode,.flat .dijitSelect.dijitSelectOpened.alt-danger .dijitArrowButton,.flat .dijitSelect.dijitSelectOpened.alt-danger .dijitButtonContents,.flat .dijitSelectHover.alt-danger .dijitButtonContents,.flat .dijitSelectHover.alt-danger .dijitButtonNode,.flat .dijitSpinner.alt-danger .dijitDownArrowButtonHover,.flat .dijitSpinner.alt-danger .dijitUpArrowButtonHover,.flat .dijitToggleButtonHover.alt-danger .dijitButtonNode{background:#e32d29;border-color:#d4201b}.flat .dijitButtonHover.alt-inverse .dijitButtonNode,.flat .dijitComboBoxHover.alt-inverse .dijitButtonNode,.flat .dijitComboButton.alt-inverse .dijitButtonNodeHover,.flat .dijitComboButton.alt-inverse .dijitDownArrowButtonHover,.flat .dijitDropDownButtonHover.alt-inverse .dijitButtonNode,.flat .dijitSelect.dijitSelectOpened.alt-inverse .dijitArrowButton,.flat .dijitSelect.dijitSelectOpened.alt-inverse .dijitButtonContents,.flat .dijitSelectHover.alt-inverse .dijitButtonContents,.flat .dijitSelectHover.alt-inverse .dijitButtonNode,.flat .dijitSpinner.alt-inverse .dijitDownArrowButtonHover,.flat .dijitSpinner.alt-inverse .dijitUpArrowButtonHover,.flat .dijitToggleButtonHover.alt-inverse .dijitButtonNode{background:#5c5c5c;border-color:#525252}.flat .dijitButtonActive .dijitButtonNode,.flat .dijitComboButton .dijitButtonNodeActive,.flat .dijitComboButton .dijitDownArrowButtonActive,.flat .dijitDropDownButtonActive .dijitButtonNode,.flat .dijitToggleButtonActive .dijitButtonNode,.flat .dijitToggleButtonChecked .dijitButtonNode{-webkit-transition:none;-moz-transition:none;-o-transition:none;-ms-transition:none;transition:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.05);box-shadow:inset 0 3px 5px rgba(0,0,0,.05);background:#e0e0e0;border-color:#b3b3b3}.flat .dijitButtonActive.alt-primary .dijitButtonNode,.flat .dijitComboBox.alt-primary .dijitButtonNode.dijitHasDropDownOpen,.flat .dijitComboBoxActive.alt-primary .dijitButtonNode,.flat .dijitComboButton.alt-primary .dijitButtonNodeActive,.flat .dijitDropDownButtonActive.alt-primary .dijitButtonNode,.flat .dijitSelect.dijitSelectOpened.alt-primary .dijitArrowButton,.flat .dijitSelect.dijitSelectOpened.alt-primary .dijitButtonContents,.flat .dijitSelectActive.alt-primary .dijitArrowButton,.flat .dijitSelectActive.alt-primary .dijitButtonContents,.flat .dijitSpinner.alt-primary .dijitDownArrowButtonActive,.flat .dijitSpinner.alt-primary .dijitUpArrowButtonActive,.flat .dijitToggleButtonActive.alt-primary .dijitButtonNode{background:#1878cc;border-color:#135fa3}.flat .dijitButtonActive.alt-success .dijitButtonNode,.flat .dijitComboBox.alt-success .dijitButtonNode.dijitHasDropDownOpen,.flat .dijitComboBoxActive.alt-success .dijitButtonNode,.flat .dijitComboButton.alt-success .dijitButtonNodeActive,.flat .dijitDropDownButtonActive.alt-success .dijitButtonNode,.flat .dijitSelect.dijitSelectOpened.alt-success .dijitArrowButton,.flat .dijitSelect.dijitSelectOpened.alt-success .dijitButtonContents,.flat .dijitSelectActive.alt-success .dijitArrowButton,.flat .dijitSelectActive.alt-success .dijitButtonContents,.flat .dijitSpinner.alt-success .dijitDownArrowButtonActive,.flat .dijitSpinner.alt-success .dijitUpArrowButtonActive,.flat .dijitToggleButtonActive.alt-success .dijitButtonNode{background:#3b8d3e;border-color:#2f7032}.flat .dijitButtonActive.alt-info .dijitButtonNode,.flat .dijitComboBox.alt-info .dijitButtonNode.dijitHasDropDownOpen,.flat .dijitComboBoxActive.alt-info .dijitButtonNode,.flat .dijitComboButton.alt-info .dijitButtonNodeActive,.flat .dijitDropDownButtonActive.alt-info .dijitButtonNode,.flat .dijitSelect.dijitSelectOpened.alt-info .dijitArrowButton,.flat .dijitSelect.dijitSelectOpened.alt-info .dijitButtonContents,.flat .dijitSelectActive.alt-info .dijitArrowButton,.flat .dijitSelectActive.alt-info .dijitButtonContents,.flat .dijitSpinner.alt-info .dijitDownArrowButtonActive,.flat .dijitSpinner.alt-info .dijitUpArrowButtonActive,.flat .dijitToggleButtonActive.alt-info .dijitButtonNode{background:#0395d7;border-color:#0276ab}.flat .dijitButtonActive.alt-warning .dijitButtonNode,.flat .dijitComboBox.alt-warning .dijitButtonNode.dijitHasDropDownOpen,.flat .dijitComboBoxActive.alt-warning .dijitButtonNode,.flat .dijitComboButton.alt-warning .dijitButtonNodeActive,.flat .dijitDropDownButtonActive.alt-warning .dijitButtonNode,.flat .dijitSelect.dijitSelectOpened.alt-warning .dijitArrowButton,.flat .dijitSelect.dijitSelectOpened.alt-warning .dijitButtonContents,.flat .dijitSelectActive.alt-warning .dijitArrowButton,.flat .dijitSelectActive.alt-warning .dijitButtonContents,.flat .dijitSpinner.alt-warning .dijitDownArrowButtonActive,.flat .dijitSpinner.alt-warning .dijitUpArrowButtonActive,.flat .dijitToggleButtonActive.alt-warning .dijitButtonNode{background:#dd7b00;border-color:#b06200}.flat .dijitButtonActive.alt-danger .dijitButtonNode,.flat .dijitComboBox.alt-danger .dijitButtonNode.dijitHasDropDownOpen,.flat .dijitComboBoxActive.alt-danger .dijitButtonNode,.flat .dijitComboButton.alt-danger .dijitButtonNodeActive,.flat .dijitDropDownButtonActive.alt-danger .dijitButtonNode,.flat .dijitSelect.dijitSelectOpened.alt-danger .dijitArrowButton,.flat .dijitSelect.dijitSelectOpened.alt-danger .dijitButtonContents,.flat .dijitSelectActive.alt-danger .dijitArrowButton,.flat .dijitSelectActive.alt-danger .dijitButtonContents,.flat .dijitSpinner.alt-danger .dijitDownArrowButtonActive,.flat .dijitSpinner.alt-danger .dijitUpArrowButtonActive,.flat .dijitToggleButtonActive.alt-danger .dijitButtonNode{background:#dc211c;border-color:#af1a17}.flat .dijitButtonActive.alt-inverse .dijitButtonNode,.flat .dijitComboBox.alt-inverse .dijitButtonNode.dijitHasDropDownOpen,.flat .dijitComboBoxActive.alt-inverse .dijitButtonNode,.flat .dijitComboButton.alt-inverse .dijitButtonNodeActive,.flat .dijitDropDownButtonActive.alt-inverse .dijitButtonNode,.flat .dijitSelect.dijitSelectOpened.alt-inverse .dijitArrowButton,.flat .dijitSelect.dijitSelectOpened.alt-inverse .dijitButtonContents,.flat .dijitSelectActive.alt-inverse .dijitArrowButton,.flat .dijitSelectActive.alt-inverse .dijitButtonContents,.flat .dijitSpinner.alt-inverse .dijitDownArrowButtonActive,.flat .dijitSpinner.alt-inverse .dijitUpArrowButtonActive,.flat .dijitToggleButtonActive.alt-inverse .dijitButtonNode{background:#555;border-color:#444}.flat .dijitButtonDisabled,.flat .dijitComboButtonDisabled,.flat .dijitDropDownButtonDisabled,.flat .dijitToggleButtonDisabled{outline:0}.flat .dijitButtonDisabled .dijitButtonNode,.flat .dijitComboButtonDisabled .dijitButtonNode,.flat .dijitDropDownButtonDisabled .dijitButtonNode,.flat .dijitToggleButtonDisabled .dijitButtonNode{cursor:default;color:#9e9e9e;background-color:#f5f5f5;border-color:#e3e3e3}.flat .dijitButtonDisabled.alt-primary .dijitButtonNode,.flat .dijitComboButtonDisabled.alt-primary .dijitButtonNode,.flat .dijitDropDownButtonDisabled.alt-primary .dijitButtonNode,.flat .dijitToggleButtonDisabled.alt-primary .dijitButtonNode{background:#6db2ee;border-color:#50a2eb;color:#f2f2f2}.flat .dijitComboBoxDisabled.alt-success .dijitButtonNode,.flat .dijitComboButtonRtlDisabled.alt-success .dijitStretch,.flat .dijitDateTextBoxDisabled.alt-success .dijitButtonNode,.flat .dijitTimeTextBoxDisabled.alt-success .dijitButtonNode{border-left-color:#63be67}.flat .dijitComboBoxRtlDisabled.alt-success .dijitButtonNode,.flat .dijitComboButtonDisabled.alt-success .dijitStretch,.flat .dijitDateTextBoxRtlDisabled.alt-success .dijitButtonNode,.flat .dijitTimeTextBoxRtlDisabled.alt-success .dijitButtonNode{border-right-color:#63be67}.flat .dijitButtonDisabled.alt-success .dijitButtonNode,.flat .dijitComboButtonDisabled.alt-success .dijitButtonNode,.flat .dijitDropDownButtonDisabled.alt-success .dijitButtonNode,.flat .dijitToggleButtonDisabled.alt-success .dijitButtonNode{background:#7dc981;border-color:#63be67;color:#f2f2f2}.flat .dijitComboBoxDisabled.alt-info .dijitButtonNode,.flat .dijitComboButtonRtlDisabled.alt-info .dijitStretch,.flat .dijitDateTextBoxDisabled.alt-info .dijitButtonNode,.flat .dijitTimeTextBoxDisabled.alt-info .dijitButtonNode{border-left-color:#34befd}.flat .dijitComboBoxRtlDisabled.alt-info .dijitButtonNode,.flat .dijitComboButtonDisabled.alt-info .dijitStretch,.flat .dijitDateTextBoxRtlDisabled.alt-info .dijitButtonNode,.flat .dijitTimeTextBoxRtlDisabled.alt-info .dijitButtonNode{border-right-color:#34befd}.flat .dijitButtonDisabled.alt-info .dijitButtonNode,.flat .dijitComboButtonDisabled.alt-info .dijitButtonNode,.flat .dijitDropDownButtonDisabled.alt-info .dijitButtonNode,.flat .dijitToggleButtonDisabled.alt-info .dijitButtonNode{background:#56c9fd;border-color:#34befd;color:#f2f2f2}.flat .dijitComboBoxDisabled.alt-warning .dijitButtonNode,.flat .dijitComboButtonRtlDisabled.alt-warning .dijitStretch,.flat .dijitDateTextBoxDisabled.alt-warning .dijitButtonNode,.flat .dijitTimeTextBoxDisabled.alt-warning .dijitButtonNode{border-left-color:#ffa635}.flat .dijitComboBoxRtlDisabled.alt-warning .dijitButtonNode,.flat .dijitComboButtonDisabled.alt-warning .dijitStretch,.flat .dijitDateTextBoxRtlDisabled.alt-warning .dijitButtonNode,.flat .dijitTimeTextBoxRtlDisabled.alt-warning .dijitButtonNode{border-right-color:#ffa635}.flat .dijitButtonDisabled.alt-warning .dijitButtonNode,.flat .dijitComboButtonDisabled.alt-warning .dijitButtonNode,.flat .dijitDropDownButtonDisabled.alt-warning .dijitButtonNode,.flat .dijitToggleButtonDisabled.alt-warning .dijitButtonNode{background:#ffb557;border-color:#ffa635;color:#f2f2f2}.flat .dijitComboBoxDisabled.alt-danger .dijitButtonNode,.flat .dijitComboButtonRtlDisabled.alt-danger .dijitStretch,.flat .dijitDateTextBoxDisabled.alt-danger .dijitButtonNode,.flat .dijitTimeTextBoxDisabled.alt-danger .dijitButtonNode{border-left-color:#eb6561}.flat .dijitComboBoxRtlDisabled.alt-danger .dijitButtonNode,.flat .dijitComboButtonDisabled.alt-danger .dijitStretch,.flat .dijitDateTextBoxRtlDisabled.alt-danger .dijitButtonNode,.flat .dijitTimeTextBoxRtlDisabled.alt-danger .dijitButtonNode{border-right-color:#eb6561}.flat .dijitButtonDisabled.alt-danger .dijitButtonNode,.flat .dijitComboButtonDisabled.alt-danger .dijitButtonNode,.flat .dijitDropDownButtonDisabled.alt-danger .dijitButtonNode,.flat .dijitToggleButtonDisabled.alt-danger .dijitButtonNode{background:#ee7e7c;border-color:#eb6561;color:#f2f2f2}.flat .dijitComboBoxDisabled.alt-inverse .dijitButtonNode,.flat .dijitComboButtonRtlDisabled.alt-inverse .dijitStretch,.flat .dijitDateTextBoxDisabled.alt-inverse .dijitButtonNode,.flat .dijitTimeTextBoxDisabled.alt-inverse .dijitButtonNode{border-left-color:#848484}.flat .dijitComboBoxRtlDisabled.alt-inverse .dijitButtonNode,.flat .dijitComboButtonDisabled.alt-inverse .dijitStretch,.flat .dijitDateTextBoxRtlDisabled.alt-inverse .dijitButtonNode,.flat .dijitTimeTextBoxRtlDisabled.alt-inverse .dijitButtonNode{border-right-color:#848484}.flat .dijitButtonDisabled.alt-inverse .dijitButtonNode,.flat .dijitComboButtonDisabled.alt-inverse .dijitButtonNode,.flat .dijitDropDownButtonDisabled.alt-inverse .dijitButtonNode,.flat .dijitToggleButtonDisabled.alt-inverse .dijitButtonNode{background:#989898;border-color:#848484;color:#f2f2f2}.flat .dijitComboButtonDisabled .dijitArrowButton{border-left-width:0}.flat .dijitDropDownButton .dijitButtonNode{padding-right:8px}.flat table.dijitComboButton .dijitStretch{-webkit-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.flat table.dijitComboButton .dijitArrowButton{padding:4px;width:20px;-webkit-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;border-left-width:0}.flat .dijitCheckBox,.flat .dijitCheckedMenuItem .dijitCheckedMenuItemIcon{border:1px solid #9e9e9e;width:16px;text-align:center;overflow:visible;height:16px}.flat .dijitToggleButtonChecked .dijitIcon{display:inline-block}.flat .dijitDropDownButton .dijitArrowButtonInner{margin-left:3px}.flat .dijitArrowButton,.flat .dijitDropDownButton .dijitArrowButtonInner{line-height:1}.flat .dijitArrowButton:before,.flat .dijitDropDownButton .dijitArrowButtonInner:before{content:"\f002"}.flat .dijitLeftArrowButton:before{content:"\f000"}.flat .dijitRightArrowButton:before{content:"\f001"}.flat .dijitUpArrowButton:before{content:"\f003"}.flat .dijitCheckBoxChecked:before,.flat .dijitCheckBoxCheckedDisabled:before,.flat .dijitCheckBoxIcon:before,.flat .dijitCheckedMenuItemChecked .dijitCheckedMenuItemIcon:before{line-height:1;font-size:16px;content:"\f00c";speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:flat-icon}.flat .dijitCheckBox{background-color:#fff;line-height:1;padding:0;-webkit-border-radius:2px;border-radius:2px;position:relative;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;-o-transition:all .1s linear;-ms-transition:all .1s linear;transition:all .1s linear}.flat .dijitCheckBox input{position:absolute;top:0}.flat .dijitCheckBoxChecked:before,.flat .dijitCheckBoxCheckedDisabled:before,.flat .dijitCheckBoxIcon:before{color:#fff}.flat .dijitCheckBoxIcon{padding:0}.flat .dijitCheckBoxIcon:before{color:#2196f3}.flat .alt-danger .dijitCheckBoxIcon:before,.flat .alt-info .dijitCheckBoxIcon:before,.flat .alt-inverse .dijitCheckBoxIcon:before,.flat .alt-primary .dijitCheckBoxIcon:before,.flat .alt-success .dijitCheckBoxIcon:before,.flat .alt-warning .dijitCheckBoxIcon:before{color:#fff}.flat .dijitCheckBoxChecked{background-color:#2196f3;border-color:#2196f3}.flat .dijitCheckBoxHover{background-color:#fff;border:1px solid #2196f3}.flat .dijitCheckBoxCheckedHover{background-color:#42a6f5;border:1px solid #2196f3}.flat .dijitCheckBoxDisabled{color:#9e9e9e;background-color:#f5f5f5;border-color:#e3e3e3}.flat .dijitCheckBoxCheckedDisabled{color:#a6a6a6;background-color:#6fbbf7;border-color:#6fbbf7}.flat .dijitCheckedMenuItem .dijitCheckedMenuItemIcon{background-color:#fff;line-height:1;padding:0;-webkit-border-radius:2px;border-radius:2px;position:relative;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;-o-transition:all .1s linear;-ms-transition:all .1s linear;transition:all .1s linear}.dijitMenuItemRtl,.dj_ie .dijitSliderRtl .dijitRuleContainerV,div.dijitNumberTextBoxRtl{text-align:right}.flat .dijitCheckedMenuItemChecked .dijitCheckedMenuItemIcon:before{color:#2196f3}.flat .dijitSpinner .dijitSpinnerButtonContainer{overflow:hidden;position:relative;width:auto;padding:0;border:1px solid #9e9e9e}.flat .dijitSpinner .dijitSpinnerButtonInner{width:30px;padding:4px 0!important;margin:0}.flat .dijitSpinner .dijitArrowButton{line-height:20px;cursor:pointer;-webkit-transition:all 50ms linear;-moz-transition:all 50ms linear;-o-transition:all 50ms linear;-ms-transition:all 50ms linear;transition:all 50ms linear;background:#fff;-webkit-border-radius:0;border-radius:0;border:0;width:auto;overflow:hidden;left:0;right:0;padding:0}.flat .dijitSpinner .dijitArrowButton:before{content:none}.flat .dijitSpinner .dijitUpArrowButton{border-top-right-radius:2px}.flat .dijitSpinner .dijitDownArrowButton{border-bottom-right-radius:2px}.flat .dijitSpinner .dijitDownArrowButtonHover,.flat .dijitSpinner .dijitUpArrowButtonHover{-webkit-transition:all .1s;-moz-transition:all .1s;-o-transition:all .1s;-ms-transition:all .1s;transition:all .1s;background:#f2f2f2;border-color:#d9d9d9}.flat .dijitSpinner .dijitDownArrowButtonActive,.flat .dijitSpinner .dijitUpArrowButtonActive{-webkit-transition:none;-moz-transition:none;-o-transition:none;-ms-transition:none;transition:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.05);box-shadow:inset 0 3px 5px rgba(0,0,0,.05);background:#e0e0e0;border-color:#b3b3b3}.flat .dijitSpinner .dijitArrowButtonInner{line-height:16px;display:block}.flat .dijitSpinner .dijitArrowButtonInner .dijitInputField{padding:0}.flat .dijitSpinner .dijitArrowButtonInner:before{content:"\f003"}.flat .dijitSpinner .dijitDownArrowButton .dijitArrowButtonInner:before{content:"\f002"}.flat .dijitSpinnerDisabled .dijitDownArrowButton,.flat .dijitSpinnerDisabled .dijitUpArrowButton{cursor:default;color:#9e9e9e;background-color:#f5f5f5;border-color:#e3e3e3}.flat .alt-primary .dijitSpinnerButtonContainer{border-color:#1e88e5}.flat .alt-success .dijitSpinnerButtonContainer{border-color:#43a047}.flat .alt-info .dijitSpinnerButtonContainer{border-color:#03a9f4}.flat .alt-warning .dijitSpinnerButtonContainer{border-color:#fb8c00}.flat .alt-danger .dijitSpinnerButtonContainer{border-color:#e53935}.flat .alt-inverse .dijitSpinnerButtonContainer{border-color:#616161}.flat .dijitRadio,.flat .dijitRadioIcon{width:16px;height:16px;background:#fff;border:1px solid #2196f3;-webkit-border-radius:50%;border-radius:50%;position:relative;overflow:visible;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.flat .dijitRadio:after,.flat .dijitRadioIcon:after{content:" ";display:block;width:0;height:0;background-color:#2196f3;-webkit-border-radius:50%;border-radius:50%;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";filter:alpha(opacity=0);margin:8px;position:absolute;top:0;left:0;-webkit-transition:all .15s ease-in-out;-moz-transition:all .15s ease-in-out;-o-transition:all .15s ease-in-out;-ms-transition:all .15s ease-in-out;transition:all .15s ease-in-out}.flat .alt-danger .dijitRadioIcon:after,.flat .alt-info .dijitRadioIcon:after,.flat .alt-inverse .dijitRadioIcon:after,.flat .alt-primary .dijitRadioIcon:after,.flat .alt-success .dijitRadioIcon:after,.flat .alt-warning .dijitRadioIcon:after{background-color:#fff}.flat .dijitRadioHover{border-color:#59b0f6}.flat .alt-danger .dijitRadioIcon,.flat .alt-info .dijitRadioIcon,.flat .alt-inverse .dijitRadioIcon,.flat .alt-primary .dijitRadioIcon,.flat .alt-success .dijitRadioIcon,.flat .alt-warning .dijitRadioIcon{border-color:#fff}.flat .dijitChecked .dijitRadioIcon:after,.flat .dijitRadioChecked:after{width:8px;height:8px;margin:3px;opacity:1;-ms-filter:none;filter:none}.flat .dijitRadioDisabled{background-color:#f5f5f5;border-color:#e3e3e3}.flat .dijitRadioCheckedDisabled{background-color:#f5f5f5;border-color:#6fbbf7}.flat .dijitRadioCheckedDisabled:after{background-color:#6fbbf7}.flat .dijitRadioMenuItem .dijitCheckedMenuItemIcon{width:16px;height:16px;background:#fff;border:1px solid #9e9e9e;-webkit-border-radius:50%;border-radius:50%;position:relative;overflow:visible;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.flat .dijitRadioMenuItemChecked .dijitCheckedMenuItemIcon,.flat .dijitSelect{border-color:#9e9e9e}.flat .dijitRadioMenuItem .dijitCheckedMenuItemIcon:after{content:" ";display:block;width:0;height:0;background-color:#2196f3;-webkit-border-radius:50%;border-radius:50%;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";filter:alpha(opacity=0);margin:8px;position:absolute;top:0;left:0;-webkit-transition:all .15s ease-in-out;-moz-transition:all .15s ease-in-out;-o-transition:all .15s ease-in-out;-ms-transition:all .15s ease-in-out;transition:all .15s ease-in-out}.flat .dijitRadioMenuItemChecked .dijitCheckedMenuItemIcon:after{width:8px;height:8px;margin:3px;opacity:1;-ms-filter:none;filter:none}.flat .dijitComboBox .dijitArrowButtonInner,.flat .dijitSelect .dijitArrowButtonInner{margin:0;width:0;height:0}.flat .dijitComboBox .dijitArrowButton,.flat .dijitSelect .dijitArrowButton{width:20px;padding:4px}.flat .dijitSelect{border-style:solid;border-width:1px;padding:4px;-webkit-border-radius:3px;border-radius:3px;line-height:20px;cursor:pointer;-webkit-transition:all 50ms linear;-moz-transition:all 50ms linear;-o-transition:all 50ms linear;-ms-transition:all 50ms linear;transition:all 50ms linear;background:#fff;table-layout:fixed}.flat .dijitSelect .dijitArrowButton,.flat .dijitSelect .dijitButtonContents{line-height:20px;padding:4px 12px;border:0;-webkit-border-radius:0 2px 2px 0;border-radius:0 2px 2px 0}.flat .dijitSelect .dijitButtonContents{padding:0;overflow:hidden;-o-text-overflow:ellipsis;text-overflow:ellipsis;-webkit-border-radius:2px 0 0 2px;border-radius:2px 0 0 2px}.flat .dijitSelect .dijitInputField{padding:0 0 0 12px}.flat .dijitSelectHover{-webkit-transition:all .1s;-moz-transition:all .1s;-o-transition:all .1s;-ms-transition:all .1s;transition:all .1s;background:#f2f2f2;border-color:#d9d9d9}.flat .dijitSelectActive{-webkit-transition:none;-moz-transition:none;-o-transition:none;-ms-transition:none;transition:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.05);box-shadow:inset 0 3px 5px rgba(0,0,0,.05);background:#e0e0e0;border-color:#b3b3b3}.flat .dijitSelectFocused{border:1px solid #9e9e9e}.flat .dijitSelectDisabled{cursor:default;color:#9e9e9e;background-color:#f5f5f5;border-color:#e3e3e3}.flat .dijitComboBox .dijitButtonNode{border-style:solid;border-width:1px;border-color:#9e9e9e;padding:4px;line-height:20px;cursor:pointer;-webkit-transition:all 50ms linear;-moz-transition:all 50ms linear;-o-transition:all 50ms linear;-ms-transition:all 50ms linear;transition:all 50ms linear;background:#fff;-webkit-border-radius:0 2px 2px 0;border-radius:0 2px 2px 0}.flat .dijitComboBox .dijitDownArrowButtonHover,.flat .dijitComboBoxOpenHover .dijitButtonNode{-webkit-transition:all .1s;-moz-transition:all .1s;-o-transition:all .1s;-ms-transition:all .1s;transition:all .1s;background:#f2f2f2;border-color:#d9d9d9;-webkit-box-shadow:none;box-shadow:none}.flat .dijitComboBoxDisabled .dijitButtonNode{cursor:default;color:#9e9e9e;background-color:#f5f5f5;border-color:#e3e3e3}.flat .dijitToolbar .dijitComboBox .dijitArrowButtonInner{border:none}.flat .dijitDateTextBox .dijitArrowButton:before{content:"\f01e"}.flat .dijitTimeTextBox .dijitArrowButton:before{content:"\f01f"}.flat select{padding:4px 0;border:1px solid #9e9e9e;-webkit-box-shadow:0 1px .5px rgba(0,0,0,.3),0 2px 2px rgba(0,0,0,.2);box-shadow:0 1px .5px rgba(0,0,0,.3),0 2px 2px rgba(0,0,0,.2)}.flat select option{padding:4px 8px}.flat .dijitRuleLabelsContainerH,.flat .dijitRuleLabelsContainerV{padding:0}.flat .dijitSelectMenu td.dijitMenuArrowCell,.flat .dijitSelectMenu td.dijitMenuItemIconCell{display:none}.flat .dijitSliderBar{border-style:solid;outline:1px}.flat .dijitRuleLabelsContainer{color:#424242;font-size:smaller}.flat .dijitSliderDisabled{opacity:.65;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=65)";filter:alpha(opacity=65)}.flat .dijitSliderBarH,.flat .dijitSliderBumperH{height:3px}.flat .dijitSlider .dijitSliderLeftBumper{-webkit-border-radius:1.5px 0 0 1.5px;border-radius:1.5px 0 0 1.5px;margin-left:4px}.flat .dijitSlider .dijitSliderRightBumper{-webkit-border-radius:0 1.5px 1.5px 0;border-radius:0 1.5px 1.5px 0;margin-left:-2px;margin-right:4px}.flat .dijitSlider .dijitSliderLeftBumper,.flat .dijitSlider .dijitSliderProgressBarH{border:0;background-color:#2196f3;background-image:none}.flat .dijitSlider .dijitSliderRemainingBarH,.flat .dijitSlider .dijitSliderRightBumper{border:0;background-color:#9e9e9e}.flat .dijitSliderHover .dijitSliderLeftBumper,.flat .dijitSliderHover .dijitSliderProgressBarH{background-color:#0d8cf1;background-image:none}.flat .dijitSliderFocused .dijitSliderLeftBumper,.flat .dijitSliderFocused .dijitSliderProgressBarH,.flat .dijitSliderFocused .dijitSliderRemainingBarH,.flat .dijitSliderFocused .dijitSliderRightBumper{-webkit-box-shadow:none;box-shadow:none}.flat .dijitSliderBarV,.flat .dijitSliderBumperV{width:3px}.flat .dijitSlider .dijitSliderTopBumper{-webkit-border-radius:1.5px 1.5px 0 0;border-radius:1.5px 1.5px 0 0;margin-top:4px;margin-bottom:-2px}.flat .dijitSlider .dijitSliderBottomBumper{-webkit-border-radius:0 0 1.5px 1.5px;border-radius:0 0 1.5px 1.5px;margin-bottom:4px}.flat .dijitSlider .dijitSliderBottomBumper,.flat .dijitSlider .dijitSliderProgressBarV{border:0;background-color:#2196f3;background-image:none}.flat .dijitSlider .dijitSliderRemainingBarV,.flat .dijitSlider .dijitSliderTopBumper{border:0;background-color:#9e9e9e}.flat .dijitSliderHover .dijitSliderBottomBumper,.flat .dijitSliderHover .dijitSliderProgressBarV{background-color:#0d8cf1;background-image:none}.flat .dijitSliderFocused .dijitSliderBottomBumper,.flat .dijitSliderFocused .dijitSliderProgressBarV,.flat .dijitSliderFocused .dijitSliderRemainingBarV,.flat .dijitSliderFocused .dijitSliderTopBumper{-webkit-box-shadow:none;box-shadow:none}.flat .dijitSliderImageHandle{background:#fff;-webkit-box-shadow:0 1px .5px rgba(0,0,0,.3),0 2px 2px rgba(0,0,0,.2);box-shadow:0 1px .5px rgba(0,0,0,.3),0 2px 2px rgba(0,0,0,.2);-webkit-border-radius:50%;border-radius:50%;border:1px solid #2196f3;width:16px;height:16px;margin-top:-2px;position:absolute;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.flat .dijitSliderImageHandle:after{content:"";display:block;background:#2196f3;-webkit-border-radius:50%;border-radius:50%;height:10px;width:10px;left:2px;top:2px;position:absolute}.flat .dijitSliderDecrementIconH .dijitSliderButtonInner,.flat .dijitSliderDecrementIconV .dijitSliderButtonInner,.flat .dijitSliderDisabled.dijitSliderFocused .dijitSliderImageHandle:after,.flat .dijitSliderIncrementIconH .dijitSliderButtonInner,.flat .dijitSliderIncrementIconV .dijitSliderButtonInner,.flat .dijitValidationTextBoxError .dijitValidationIcon{display:none}.flat .dijitSliderImageHandleV{margin-top:0}.flat .dijitSliderFocused .dijitSliderImageHandle,.flat .dijitSliderHover .dijitSliderImageHandle{-webkit-box-shadow:0 4px 2px -2px rgba(0,0,0,.3),0 4px 6px rgba(0,0,0,.2);box-shadow:0 4px 2px -2px rgba(0,0,0,.3),0 4px 6px rgba(0,0,0,.2)}.flat .dijitSliderDecrementIconH,.flat .dijitSliderDecrementIconV,.flat .dijitSliderIncrementIconH,.flat .dijitSliderIncrementIconV{border-style:solid;border-width:1px;border-color:#9e9e9e;-webkit-border-radius:3px;border-radius:3px;-webkit-transition:all 50ms linear;-moz-transition:all 50ms linear;-o-transition:all 50ms linear;-ms-transition:all 50ms linear;transition:all 50ms linear;background:#fff;height:20px;width:20px;cursor:pointer;color:#2196f3;padding:0;font-family:flat-icon;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;font-size:16px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.flat .dijitSliderDecrementIconH:hover,.flat .dijitSliderDecrementIconV:hover,.flat .dijitSliderIncrementIconH:hover,.flat .dijitSliderIncrementIconV:hover{-webkit-transition:all .1s;-moz-transition:all .1s;-o-transition:all .1s;-ms-transition:all .1s;transition:all .1s;background:#f2f2f2;border-color:#d9d9d9}.flat .dijitSliderDecrementIconH:active,.flat .dijitSliderDecrementIconV:active,.flat .dijitSliderIncrementIconH:active,.flat .dijitSliderIncrementIconV:active{-webkit-transition:none;-moz-transition:none;-o-transition:none;-ms-transition:none;transition:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.05);box-shadow:inset 0 3px 5px rgba(0,0,0,.05);background:#e0e0e0;border-color:#b3b3b3}.flat .dijitSliderDisabled .dijitSliderDecrementIconH,.flat .dijitSliderDisabled .dijitSliderDecrementIconV,.flat .dijitSliderDisabled .dijitSliderIncrementIconH,.flat .dijitSliderDisabled .dijitSliderIncrementIconV,.flat .dijitSliderReadOnly .dijitSliderDecrementIconH,.flat .dijitSliderReadOnly .dijitSliderDecrementIconV,.flat .dijitSliderReadOnly .dijitSliderIncrementIconH,.flat .dijitSliderReadOnly .dijitSliderIncrementIconV{opacity:.65;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=65)";filter:alpha(opacity=65)}.flat .dijitSliderDecrementIconH:before,.flat .dijitSliderDecrementIconV:before,.flat .dijitSliderIncrementIconH:before,.flat .dijitSliderIncrementIconV:before{content:"\f011";top:0;line-height:20px}.flat .dijitSliderDecrementIconH:before,.flat .dijitSliderDecrementIconV:before{content:"\f012"}.flat .dijitRuleMark{border:0}.flat .dijitRuleMarkH{border-right:1px solid #e0e0e0}.flat .dijitRuleMarkV{border-bottom:1px solid #e0e0e0}.flat .dijitRuleLabelContainerH{margin-top:2px;margin-bottom:2px}.flat .dijitRuleLabelContainerV{margin-left:2px;margin-right:2px}.flat .dijitInputInner,.flat .dijitTextBox{line-height:20px}.dijitEditorIcon,.dijitIcon,.flat .dijitValidationTextBoxError .dijitValidationContainer,[class*=" flat-"],[class^=flat-]{speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.flat .dijitTextBox{background:#fff;border:1px solid #9e9e9e;-webkit-border-radius:3px;border-radius:3px;-webkit-transition:border .2s linear 0s,box-shadow .2s linear 0s;-moz-transition:border .2s linear 0s,box-shadow .2s linear 0s;-o-transition:border .2s linear 0s,box-shadow .2s linear 0s;-ms-transition:border .2s linear 0s,box-shadow .2s linear 0s;transition:border .2s linear 0s,box-shadow .2s linear 0s}.flat .dijitTextArea{padding:4px 6px}.flat .dijitTextBox .dijitInputField{padding:0 4px;margin:0 2px}.flat .dijitComboBox.alt-primary,.flat .dijitSelect.alt-primary,.flat .dijitSpinner.alt-primary{border-color:#1e88e5}.flat .dijitComboBox.alt-success,.flat .dijitSelect.alt-success,.flat .dijitSpinner.alt-success{border-color:#43a047}.flat .dijitComboBox.alt-info,.flat .dijitSelect.alt-info,.flat .dijitSpinner.alt-info{border-color:#03a9f4}.flat .dijitComboBox.alt-warning,.flat .dijitSelect.alt-warning,.flat .dijitSpinner.alt-warning{border-color:#fb8c00}.flat .dijitComboBox.alt-danger,.flat .dijitSelect.alt-danger,.flat .dijitSpinner.alt-danger{border-color:#e53935}.flat .dijitComboBox.alt-inverse,.flat .dijitSelect.alt-inverse,.flat .dijitSpinner.alt-inverse{border-color:#616161}.flat .dijitTextBox .dijitInputField .dijitPlaceHolder,.flat .dijitTextBox .dijitInputInner,.flat .dijitValidationTextBox .dijitValidationContainer{padding:4px}.flat .dijitTextBoxHover{border-color:#2196f3;-webkit-transition-duration:.25s;-moz-transition-duration:.25s;-o-transition-duration:.25s;-ms-transition-duration:.25s;transition-duration:.25s}.flat .dijitTextBoxFocused{border-color:#2196f3;-webkit-transition-duration:.1s;-moz-transition-duration:.1s;-o-transition-duration:.1s;-ms-transition-duration:.1s;transition-duration:.1s}.flat .dijitTextBoxDisabled{color:#9e9e9e;background-color:#f5f5f5;border-color:#e3e3e3}.flat .dijitComboBoxDisabled.alt-primary,.flat .dijitSpinnerDisabled.alt-primary{background:#f5f5f5;color:#9e9e9e;border:1px solid #6db2ee}.flat .dijitComboBoxDisabled.alt-primary .dijitButtonNode,.flat .dijitSelectDisabled.alt-primary .dijitButtonNode,.flat .dijitSelectDisabled.alt-primary .dijitStretch,.flat .dijitSpinnerDisabled.alt-primary .dijitButtonNode{background:#6db2ee;color:#f2f2f2}.flat .dijitSpinnerDisabled.alt-primary .dijitSpinnerButtonContainer{border-left-color:#6db2ee}.flat .dijitSpinnerRtlDisabled.alt-primary .dijitSpinnerButtonContainer{border-right-color:#6db2ee}.flat .dijitSelectDisabled.alt-primary{border-color:#6db2ee}.flat .dijitComboBoxDisabled.alt-success,.flat .dijitSpinnerDisabled.alt-success{background:#f5f5f5;color:#9e9e9e;border:1px solid #7dc981}.flat .dijitComboBoxDisabled.alt-success .dijitButtonNode,.flat .dijitSelectDisabled.alt-success .dijitButtonNode,.flat .dijitSelectDisabled.alt-success .dijitStretch,.flat .dijitSpinnerDisabled.alt-success .dijitButtonNode{background:#7dc981;color:#f2f2f2}.flat .dijitSpinnerDisabled.alt-success .dijitSpinnerButtonContainer{border-left-color:#7dc981}.flat .dijitSpinnerRtlDisabled.alt-success .dijitSpinnerButtonContainer{border-right-color:#7dc981}.flat .dijitSelectDisabled.alt-success{border-color:#7dc981}.flat .dijitComboBoxDisabled.alt-info,.flat .dijitSpinnerDisabled.alt-info{background:#f5f5f5;color:#9e9e9e;border:1px solid #56c9fd}.flat .dijitComboBoxDisabled.alt-info .dijitButtonNode,.flat .dijitSelectDisabled.alt-info .dijitButtonNode,.flat .dijitSelectDisabled.alt-info .dijitStretch,.flat .dijitSpinnerDisabled.alt-info .dijitButtonNode{background:#56c9fd;color:#f2f2f2}.flat .dijitSpinnerDisabled.alt-info .dijitSpinnerButtonContainer{border-left-color:#56c9fd}.flat .dijitSpinnerRtlDisabled.alt-info .dijitSpinnerButtonContainer{border-right-color:#56c9fd}.flat .dijitSelectDisabled.alt-info{border-color:#56c9fd}.flat .dijitComboBoxDisabled.alt-warning,.flat .dijitSpinnerDisabled.alt-warning{background:#f5f5f5;color:#9e9e9e;border:1px solid #ffb557}.flat .dijitComboBoxDisabled.alt-warning .dijitButtonNode,.flat .dijitSelectDisabled.alt-warning .dijitButtonNode,.flat .dijitSelectDisabled.alt-warning .dijitStretch,.flat .dijitSpinnerDisabled.alt-warning .dijitButtonNode{background:#ffb557;color:#f2f2f2}.flat .dijitSpinnerDisabled.alt-warning .dijitSpinnerButtonContainer{border-left-color:#ffb557}.flat .dijitSpinnerRtlDisabled.alt-warning .dijitSpinnerButtonContainer{border-right-color:#ffb557}.flat .dijitSelectDisabled.alt-warning{border-color:#ffb557}.flat .dijitComboBoxDisabled.alt-danger,.flat .dijitSpinnerDisabled.alt-danger{background:#f5f5f5;color:#9e9e9e;border:1px solid #ee7e7c}.flat .dijitComboBoxDisabled.alt-danger .dijitButtonNode,.flat .dijitSelectDisabled.alt-danger .dijitButtonNode,.flat .dijitSelectDisabled.alt-danger .dijitStretch,.flat .dijitSpinnerDisabled.alt-danger .dijitButtonNode{background:#ee7e7c;color:#f2f2f2}.flat .dijitSpinnerDisabled.alt-danger .dijitSpinnerButtonContainer{border-left-color:#ee7e7c}.flat .dijitSpinnerRtlDisabled.alt-danger .dijitSpinnerButtonContainer{border-right-color:#ee7e7c}.flat .dijitSelectDisabled.alt-danger{border-color:#ee7e7c}.flat .dijitComboBoxDisabled.alt-inverse,.flat .dijitSpinnerDisabled.alt-inverse{background:#f5f5f5;color:#9e9e9e;border:1px solid #989898}.flat .dijitComboBoxDisabled.alt-inverse .dijitButtonNode,.flat .dijitSelectDisabled.alt-inverse .dijitButtonNode,.flat .dijitSelectDisabled.alt-inverse .dijitStretch,.flat .dijitSpinnerDisabled.alt-inverse .dijitButtonNode{background:#989898;color:#f2f2f2}.flat .dijitSpinnerDisabled.alt-inverse .dijitSpinnerButtonContainer{border-left-color:#989898}.flat .dijitSpinnerRtlDisabled.alt-inverse .dijitSpinnerButtonContainer{border-right-color:#989898}.flat .dijitSelectDisabled.alt-inverse{border-color:#989898}.flat .dijitTextBoxError,.flat .dijitTextBoxError .dijitButtonNode{border-color:#dd2c00}.flat .dijitTextBoxErrorFocused,.flat .dijitTextBoxErrorFocused .dijitButtonNode{border:1px solid #bc2500}.flat .dijitValidationTextBoxError .dijitValidationContainer{color:#dd2c00;width:18px;font-family:flat-icon;font-size:18px}.flat .dijitValidationTextBoxError .dijitValidationContainer:before{content:"\f017"}@font-face{font-family:flat-icon;src:url(fonts/flat-icon.eot?90nq1s);src:url(fonts/flat-icon.eot?#iefix90nq1s) format('embedded-opentype'),url(fonts/flat-icon.ttf?90nq1s) format('truetype'),url(fonts/flat-icon.woff?90nq1s) format('woff'),url(fonts/flat-icon.svg?90nq1s#flat-icon) format('svg');font-weight:400;font-style:normal}[class*=" flat-"],[class^=flat-]{font-family:flat-icon}.dijitEditorIcon,.dijitIcon{font-family:flat-icon;font-size:16px;width:16px;height:16px}.flat-drop-left:before{content:"\f000"}.flat-drop-right:before{content:"\f001"}.flat-drop-down:before{content:"\f002"}.flat-drop-up:before{content:"\f003"}.flat-chevron-left:before{content:"\f004"}.flat-chevron-right:before{content:"\f005"}.flat-chevron-down:before{content:"\f006"}.flat-chevron-up:before{content:"\f007"}.flat-arrow-left:before{content:"\f008"}.flat-arrow-right:before{content:"\f009"}.flat-arrow-down:before{content:"\f00a"}.flat-arrow-up:before{content:"\f00b"}.flat-check:before{content:"\f00c"}.flat-check-circle:before{content:"\f00d"}.flat-close:before{content:"\f00e"}.dijitIconClear:before,.flat-close-circle:before{content:"\f00f"}.dijitEditorIconCancel:before,.flat-close-circle-o:before{content:"\f010"}.flat-add:before{content:"\f011"}.flat-remove:before{content:"\f012"}.flat-add-circle:before{content:"\f013"}.flat-remove-circle:before{content:"\f014"}.flat-add-circle-o:before{content:"\f015"}.flat-remove-circle-o:before{content:"\f016"}.dijitIconError:before,.flat-error:before{content:"\f017"}.flat-error-o:before{content:"\f018"}.flat-warning:before{content:"\f019"}.flat-report:before{content:"\f01a"}.flat-help:before{content:"\f01b"}.flat-no-symbol:before{content:"\f01c"}.flat-update:before{content:"\f01d"}.flat-calendar:before{content:"\f01e"}.flat-clock:before{content:"\f01f"}.dijitFolderClosed:before,.dijitIconFolderClosed:before,.flat-folder:before{content:"\f020"}.dijitFolderOpened:before,.dijitIconFolderOpen:before,.flat-folder-open:before{content:"\f021"}.dijitIconEdit:before,.flat-edit:before{content:"\f022"}.dijitEditorIconSave:before,.dijitIconSave:before,.flat-save:before{content:"\f023"}.dijitEditorIconPrint:before,.dijitIconPrint:before,.flat-print:before{content:"\f024"}.dijitEditorIconDelete:before,.dijitIconDelete:before,.flat-delete:before{content:"\f025"}.dijitLeaf:before,.flat-page:before{content:"\f026"}.flat-page-o:before{content:"\f027"}.flat-page-add:before{content:"\f028"}.flat-page-remove:before{content:"\f029"}.flat-page-add-o:before{content:"\f02a"}.flat-page-remove-o:before{content:"\f02b"}.dijitIconFile:before,.flat-file:before{content:"\f02c"}.dijitIconMail:before,.flat-mail:before{content:"\f02d"}.dijitIconDatabase:before,.flat-storage:before{content:"\f02e"}.dijitIconConfigure:before,.flat-settings:before{content:"\f02f"}.dijitIconSearch:before,.flat-search:before{content:"\f030"}.dijitIconBookmark:before,.flat-bookmark:before{content:"\f031"}.flat-menu:before{content:"\f032"}.dijitIconApplication:before,.flat-application:before{content:"\f033"}.dijitIconKey:before,.flat-key:before{content:"\f034"}.dijitEditorIconInsertTable:before,.dijitIconTable:before,.flat-table:before{content:"\f035"}.flat-grid:before{content:"\f036"}.dijitIconChart:before,.flat-chart:before{content:"\f037"}.dijitIconFilter:before,.flat-filter:before{content:"\f038"}.dijitIconFunction:before,.flat-function:before{content:"\f039"}.flat-user:before{content:"\f03a"}.dijitIconUsers:before,.flat-users:before{content:"\f03b"}.dijitIconConnector:before,.flat-connector:before{content:"\f03c"}.dijitIconDocuments:before,.flat-documents:before{content:"\f03d"}.dijitIconEditProperty:before,.flat-edit-property:before{content:"\f03e"}.dijitIconTask:before,.flat-task:before{content:"\f03f"}.dijitIconNewTask:before,.flat-task-new:before{content:"\f040"}.dijitIconEditTask:before,.flat-task-edit:before{content:"\f041"}.dijitIconSample:before,.flat-sample:before{content:"\f042"}.dijitIconPackage:before,.flat-package:before{content:"\f043"}.dijitEditorIconUndo:before,.flat-undo:before{content:"\f044"}.dijitEditorIconRedo:before,.flat-redo:before{content:"\f045"}.dijitEditorIconCopy:before,.dijitIconCopy:before,.flat-copy:before{content:"\f046"}.dijitEditorIconCut:before,.dijitIconCut:before,.flat-cut:before{content:"\f047"}.dijitEditorIconPaste:before,.flat-paste:before{content:"\f048"}.dijitEditorIconBold:before,.flat-bold:before{content:"\f049"}.dijitEditorIconItalic:before,.flat-italic:before{content:"\f04a"}.dijitEditorIconUnderline:before,.flat-underline:before{content:"\f04b"}.dijitEditorIconStrikethrough:before,.flat-strikethrough:before{content:"\f04c"}.dijitEditorIconRemoveFormat:before,.flat-clear-format:before{content:"\f04d"}.flat-quote:before{content:"\f04e"}.dijitEditorIconSuperscript:before,.flat-superscript:before{content:"\f04f"}.dijitEditorIconSubscript:before,.flat-subscript:before{content:"\f050"}.dijitEditorIconForeColor:before,.flat-color-text:before{content:"\f051"}.dijitEditorIconBackColor:before,.flat-color-fill:before{content:"\f052"}.dijitEditorIconHiliteColor:before,.flat-color-highlight:before{content:"\f053"}.flat-font-size:before{content:"\f054"}.dijitEditorIconJustifyCenter:before,.flat-align-center:before{content:"\f055"}.dijitEditorIconJustifyFull:before,.flat-align-justify:before{content:"\f056"}.dijitEditorIconJustifyLeft:before,.flat-align-left:before{content:"\f057"}.dijitEditorIconJustifyRight:before,.flat-align-right:before{content:"\f058"}.dijitEditorIconIndent:before,.flat-indent:before{content:"\f059"}.dijitEditorIconOutdent:before,.flat-outdent:before{content:"\f05a"}.flat-sort:before{content:"\f05b"}.dijitEditorIconSpace:before,.flat-keyboard-space:before{content:"\f05c"}.dijitEditorIconTabIndent:before,.flat-keyboard-tab:before{content:"\f05d"}.dijitEditorIconInsertUnorderedList:before,.flat-list-bullet:before{content:"\f05e"}.dijitEditorIconInsertOrderedList:before,.flat-list-number:before{content:"\f05f"}.dijitEditorIconListBulletIndent:before,.flat-list-bullet-indent:before{content:"\f060"}.dijitEditorIconListBulletOutdent:before,.flat-list-bullet-outdent:before{content:"\f061"}.dijitEditorIconListNumIndent:before,.flat-list-number-indent:before{content:"\f062"}.dijitEditorIconListNumOutdent:before,.flat-list-number-outdent:before{content:"\f063"}.dijitEditorIconViewSource:before,.flat-code:before{content:"\f064"}.dijitEditorIconCreateLink:before,.flat-link:before{content:"\f065"}.dijitEditorIconUnlink:before,.flat-unlink:before{content:"\f066"}.dijitEditorIconFullScreen:before,.flat-fullscreen:before{content:"\f067"}.flat-fullscreen-exit:before{content:"\f068"}.dijitEditorIconInsertImage:before,.flat-image:before{content:"\f069"}.dijitEditorIconNewPage:before,.flat-page-new:before{content:"\f06a"}.dijitEditorIconToggleDir:before,.flat-toggle-dir:before{content:"\f06b"}.dijitEditorIconLeftToRight:before,.flat-left-to-right:before{content:"\f06c"}.dijitEditorIconRightToLeft:before,.flat-right-to-left:before{content:"\f06d"}.dijitEditorIconSelectAll:before,.flat-select-all:before{content:"\f06e"}.dijitEditorIconWikiword:before,.flat-wikiword:before{content:"\f06f"}.icon-spin{-webkit-animation:spin-right 2s infinite linear;-moz-animation:spin-right 2s infinite linear;-o-animation:spin-right 2s infinite linear;-ms-animation:spin-right 2s infinite linear;animation:spin-right 2s infinite linear}.dijitIconLoading{font-size:24px}.dijitIconLoading:before{content:"\f01d";-webkit-animation:spin-left 2s linear infinite;-moz-animation:spin-left 2s linear infinite;-o-animation:spin-left 2s linear infinite;-ms-animation:spin-left 2s linear infinite;animation:spin-left 2s linear infinite}.dj_ie8 .dijitIconLoading,.dj_ie9 .dijitIconLoading{background:url(images/loadingAnimation.gif) no-repeat;height:20px;width:20px}.dj_ie8 .dijitIconLoading:before,.dj_ie9 .dijitIconLoading:before{content:""}.dijitRtl .dijitEditorIconRedo:before,.dijitRtl .dijitEditorIconUndo:before{content:"\f044"}.dijitRtl .dijitEditorIconTabIndent:before{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.dijitRtl .dijitEditorIconInsertOrderedList,.dijitRtl .dijitEditorIconInsertUnorderedList{-webkit-transform:scale(-1,1);-moz-transform:scale(-1,1);-o-transform:scale(-1,1);-ms-transform:scale(-1,1);transform:scale(-1,1)}:root .dijitRtl .dijitEditorIconInsertOrderedList,:root .dijitRtl .dijitEditorIconInsertUnorderedList{filter:none}@-moz-keyframes spin-right{from{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes spin-right{from{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-o-keyframes spin-right{from{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spin-right{from{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes spin-left{from{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}to{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}}@-webkit-keyframes spin-left{from{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}to{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}}@-o-keyframes spin-left{from{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}to{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}}@keyframes spin-left{from{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}to{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}}.dijitRtl .dijitOffScreen{left:auto!important;right:-10000px!important}.dijitRtl .dijitPlaceHolder,.dijitSpinnerRtl .dijitSpinnerButtonContainer .dijitArrowButton{right:0;left:auto}.dj_iequirks .dijitComboButtonRtl button{float:left}.dj_ie .dijitTextBoxRtl .dijitInputContainer{clear:right}.dijitComboBoxRtl .dijitArrowButtonContainer,.dijitTextBoxRtl .dijitSpinnerButtonContainer,.dijitTextBoxRtl .dijitValidationContainer{border-right-width:1px!important;border-left-width:0!important}.dijitSelectRtl .dijitButtonText{float:right}.dijitTextBoxRtl .dijitArrowButtonContainer,.dijitTextBoxRtl .dijitSpinnerButtonContainer,.dijitValidationTextBoxRtl .dijitValidationContainer{float:left}.dijitSliderRtl .dijitRuleContainerV,.dijitTreeRtl .dijitTreeContainer,.flat .dijitTreeRtl .dijitTreeContainer{float:right}.dijitCalendarRtl .dijitCalendarNextYear{margin:0 .55em 0 0}.dijitCalendarRtl .dijitCalendarPreviousYear{margin:0 0 0 .55em}.dijitSliderRtl .dijitSliderImageHandleV{left:auto}.dijitSliderRtl .dijitSliderImageHandleH{left:-50%}.dijitSliderRtl .dijitSliderMoveableH{right:auto;left:0}.dj_ie .dijitSliderRtl .dijitRuleLabelV{text-align:left}.dijitSliderRtl .dijitSliderProgressBarH{float:right;right:0;left:auto}.dijitRtl .dijitContentPaneError .dijitIconError,.dijitRtl .dijitContentPaneLoading .dijitIconLoading{margin-right:0;margin-left:9px}.dijitTabControllerRtl .nowrapTabStrip{text-align:right}.dijitTabRtl .dijitTabCloseButton{margin-left:0;margin-right:1em}.dj_ie6 .dijitTabContainerRight-tabs .dijitTabRtl,.dj_ie7 .dijitTabContainerRight-tabs .dijitTabRtl{left:0}.dijitColorPaletteRtl .dijitColorPaletteUnder,.flat .dijitColorPaletteRtl .dijitColorPaletteUnder{left:auto;right:0}.dj_ie6 .dijitTabContainerLeftRtl .dijitTabContainerLeft-tabs,.dj_ie6 .dijitTabContainerRightRtl .dijitTabContainerRight-tabs{width:1%}.dj_ie .dijitTimePickerRtl .dijitTimePickerItem{width:100%}.dijitSelectRtl .dijitButtonContents{border-style:none none none solid;text-align:right}.dijitRtl .dojoDndHorizontal .dojoDndItemBefore{border-width:0 2px 0 0;padding:2px 0 2px 2px}.dijitRtl .dojoDndHorizontal .dojoDndItemAfter{border-width:0 0 0 2px;padding:2px 2px 2px 0}.flat .dijitCalendarRtl .dijitCalendarDecrease:before{content:"\f001"}.flat .dijitCalendarRtl .dijitCalendarIncrease:before,.flat .dijitMenuItemRtl .dijitMenuExpand:before{content:"\f000"}.flat .dijitDialogRtl .dijitDialogCloseIcon{right:auto;left:12px}.flat .dijitDialogRtl .dijitDialogPaneActionBar,.flat .dijitTooltipDialogRtl .dijitDialogPaneActionBar{text-align:left}.flat .dijitMenuBarRtl,.flat .dijitMenuItemRtl,.flat .dijitTabControllerRtl,.flat .dijitTabControllerRtl .nowrapTabStrip,.flat .dijitTitlePaneRtl .dijitTitlePaneTitle,.flat .dijitTreeRtl,.flat div.dijitNumberTextBoxRtl{text-align:right}.flat .dijitTitlePaneRtl .dijitClosed .dijitArrowNode:before{content:"\f006"}.flat .dijitToolbar .dijitButtonRtl,.flat .dijitToolbar .dijitComboButtonRtl,.flat .dijitToolbar .dijitDropDownButtonRtl,.flat .dijitToolbar .dijitToggleButtonRtl{margin-left:4px;margin-right:auto}.flat .dijitToolbar .dijitDropDownButtonRtl .dijitArrowButtonInner{margin-left:auto;margin-right:4px}.flat .dijitTreeRtl .dijitTreeExpandoClosed:before{content:"\e60b"}.flat .dijitAccordionTitle .arrowTextDown,.flat .dijitAccordionTitle .arrowTextUp{float:left}.flat .dijitTabContainerBottom-tabs .dijitTabRtl,.flat .dijitTabContainerTop-tabs .dijitTabRtl{margin-right:0;margin-left:-1px}.flat .dijitTabRtl .dijitTabCloseButton{margin-left:0;margin-right:4px}.flat table.dijitComboButtonRtl .dijitStretch{-webkit-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.flat table.dijitComboButtonRtl .dijitArrowButton{-webkit-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;border-left-width:1px;border-right-width:0}.flat .dijitDropDownButtonRtl .dijitButtonNode{padding-left:8px}.flat .dijitDropDownButtonRtl .dijitArrowButtonInner{margin-left:0;margin-right:12px}.flat .dijitSpinnerRtl .dijitSpinnerButtonContainer .dijitArrowButton{right:0;left:auto}.flat .dijitSelectRtl .dijitButtonText{float:right;padding:0 12px 0 0}.flat .dijitSelectRtl .dijitButtonContents{border-style:none none none solid;text-align:right}.flat .dijitComboBoxRtl .dijitButtonNode.dijitArrowButtonContainer{-webkit-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.flat .dijitComboBoxRtl .dijitArrowButtonContainer{border-right-width:1px!important;border-left-width:0!important}.flat .dijitSliderRtl .dijitSliderProgressBarH{float:right;right:0;left:auto}.flat .dijitSliderRtl .dijitSliderLeftBumper{border-left-width:0;border-right-width:1px;margin-left:0;margin-right:4px;-webkit-border-radius:0 1.5px 1.5px 0;border-radius:0 1.5px 1.5px 0}.flat .dijitSliderRtl .dijitSliderRightBumper{border-left-width:1px;border-right-width:0;margin-left:4px;margin-right:-2px;-webkit-border-radius:1.5px 0 0 1.5px;border-radius:1.5px 0 0 1.5px}.flat .dijitSliderRtl .dijitSliderMoveableH{right:auto;left:0}.flat .dijitSliderRtl .dijitSliderImageHandleV{left:auto}.flat .dijitSliderRtl .dijitSliderImageHandleH{left:-50%}.flat .dijitSliderRtl .dijitRuleContainerV{float:right}.flat .dijitTextBoxRtl .dijitSpinnerButtonContainer,.flat .dijitTextBoxRtl .dijitValidationContainer{border-right-width:1px!important;border-left-width:0!important}.flat .dijitTextBoxRtlError .dijitValidationContainer{border-left-width:0;border-right-width:1px}.flat .dijitRtl .dijitPlaceHolder{left:auto;right:0}.flat .dijitTextBoxRtl .dijitArrowButtonContainer,.flat .dijitTextBoxRtl .dijitSpinnerButtonContainer,.flat .dijitValidationTextBoxRtl .dijitValidationContainer{float:left} \ No newline at end of file diff --git a/viewer/css/theme/flat/fonts/flat-icon.eot b/viewer/css/theme/flat/fonts/flat-icon.eot new file mode 100644 index 000000000..803a04220 Binary files /dev/null and b/viewer/css/theme/flat/fonts/flat-icon.eot differ diff --git a/viewer/css/theme/flat/fonts/flat-icon.svg b/viewer/css/theme/flat/fonts/flat-icon.svg new file mode 100644 index 000000000..60db68b50 --- /dev/null +++ b/viewer/css/theme/flat/fonts/flat-icon.svg @@ -0,0 +1,122 @@ + + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/viewer/css/theme/flat/fonts/flat-icon.ttf b/viewer/css/theme/flat/fonts/flat-icon.ttf new file mode 100644 index 000000000..96d0c500a Binary files /dev/null and b/viewer/css/theme/flat/fonts/flat-icon.ttf differ diff --git a/viewer/css/theme/flat/fonts/flat-icon.woff b/viewer/css/theme/flat/fonts/flat-icon.woff new file mode 100644 index 000000000..a62cb0b77 Binary files /dev/null and b/viewer/css/theme/flat/fonts/flat-icon.woff differ diff --git a/viewer/css/theme/flat/images/loadingAnimation.gif b/viewer/css/theme/flat/images/loadingAnimation.gif new file mode 100644 index 000000000..694e2cb3f Binary files /dev/null and b/viewer/css/theme/flat/images/loadingAnimation.gif differ diff --git a/viewer/css/theme/flat/images/progressBarStrips.png b/viewer/css/theme/flat/images/progressBarStrips.png new file mode 100644 index 000000000..50644f98c Binary files /dev/null and b/viewer/css/theme/flat/images/progressBarStrips.png differ diff --git a/viewer/favicon.png b/viewer/favicon.png new file mode 100644 index 000000000..9ac1f0f7d Binary files /dev/null and b/viewer/favicon.png differ diff --git a/viewer/index.html b/viewer/index.html index 8cbf2bdbb..6dbebc88c 100644 --- a/viewer/index.html +++ b/viewer/index.html @@ -6,13 +6,18 @@ + + + + Configurable Map Viewer - - - + + + + - +
- - + + diff --git a/viewer/js/config/app.js b/viewer/js/config/app.js new file mode 100644 index 000000000..f83155e22 --- /dev/null +++ b/viewer/js/config/app.js @@ -0,0 +1,79 @@ +(function () { + var path = location.pathname.replace(/[^\/]+$/, ''); + window.dojoConfig = { + async: true, + packages: [ + { + name: 'viewer', + location: path + 'js/viewer' + }, { + name: 'gis', + location: path + 'js/gis' + }, { + name: 'config', + location: path + 'js/config' + }, { + name: 'proj4js', + location: '//cdnjs.cloudflare.com/ajax/libs/proj4js/2.3.15' + }, { + name: 'flag-icon-css', + location: '//cdnjs.cloudflare.com/ajax/libs/flag-icon-css/2.8.0' + } + ] + }; + + require(window.dojoConfig, [ + 'dojo/_base/declare', + + // minimal Base Controller + 'viewer/_ControllerBase', + + // *** Controller Mixins + // Use the core mixins, add custom mixins + // or replace core mixins with your own + 'viewer/_ConfigMixin', // manage the Configuration + 'viewer/_LayoutMixin', // build and manage the Page Layout and User Interface + 'viewer/_MapMixin', // build and manage the Map + 'viewer/_WidgetsMixin' // build and manage the Widgets + + // 'viewer/_WebMapMixin' // for WebMaps + //'config/_customMixin' + + ], function ( + declare, + + _ControllerBase, + _ConfigMixin, + _LayoutMixin, + _MapMixin, + _WidgetsMixin + + // _WebMapMixin + //_MyCustomMixin + + ) { + var App = declare([ + + // add custom mixins here...note order may be important and + // overriding certain methods incorrectly may break the app + // First on the list are last called last, for instance the startup + // method on _ControllerBase is called FIRST, and _LayoutMixin is called LAST + // for the most part they are interchangeable, except _ConfigMixin + // and _ControllerBase + // + _LayoutMixin, + _WidgetsMixin, + // _WebMapMixin, + _MapMixin, + + // configMixin should be right before _ControllerBase so it is + // called first to initialize the config object + _ConfigMixin, + + // controller base needs to be last + _ControllerBase + ]); + var app = new App(); + app.startup(); + }); +})(); diff --git a/viewer/js/config/basemaps.js b/viewer/js/config/basemaps.js index 49a91a5cf..d6d7aa074 100644 --- a/viewer/js/config/basemaps.js +++ b/viewer/js/config/basemaps.js @@ -1,52 +1,198 @@ define([ - //'esri/dijit/Basemap', - //'esri/dijit/BasemapLayer', - //'esri/layers/osm' -], function ( /* Basemap, BasemapLayer, osm */ ) { + 'esri/dijit/Basemap', + 'esri/dijit/BasemapLayer', + 'dojo/i18n!./nls/main' +], function (Basemap, BasemapLayer, i18n) { + return { - map: true, // needs a refrence to the map - mode: 'agol', //must be either 'agol' or 'custom' - title: 'Basemaps', // tilte for widget - mapStartBasemap: 'streets', // must match one of the basemap keys below - //basemaps to show in menu. define in basemaps object below and reference by name here - // TODO Is this array necessary when the same keys are explicitly included/excluded below? - basemapsToShow: ['streets', 'satellite', 'hybrid', 'topo', 'lightGray', 'gray', 'national-geographic', 'osm', 'oceans'], + map: true, // needs a reference to the map + //mode: 'agol', // mut be either 'agol' or 'custom' - // define all valid custom basemaps here. Object of Basemap objects. For custom basemaps, the key name and basemap id must match. - basemaps: { // agol basemaps - streets: { - title: 'Streets' + /* optional starting basemap + / otherwise uses the basemap from the map + / must match one of the keys in basemaps object below + */ + //mapStartBasemap: 'streets', + + /* optional array of basemaps to show in menu. + / otherwise uses keys in basemaps object below + / values in array must match keys in basemaps object + */ + //basemapsToShow: ['streets', 'satellite', 'hybrid', 'topo', 'lightGray', 'gray', 'national-geographic', 'osm', 'oceans'], + + // define all valid basemaps here. + basemaps: { + streets: {}, + 'streets-night-vector': {}, // requires v3.16 or higher + 'streets-navigation-vector': {}, // requires v3.16 or higher + 'streets-relief-vector': {}, // requires v3.16 or higher + satellite: {}, + hybrid: {}, + topo: {}, + terrain: {}, + 'gray-vector': {}, // requires v3.16 or higher + 'dark-gray-vector': {}, // requires v3.16 or higher + oceans: {}, + 'national-geographic': {}, + osm: {}, + landsatShaded: { + title: i18n.basemaps.landsatShaded, + basemap: { + baseMapLayers: [ + { + url: 'https://imagery.arcgisonline.com/arcgis/rest/services/LandsatGLS/LandsatShadedBasemap/ImageServer' + } + ] + } }, - satellite: { - title: 'Satellite' + earthAtNight: { + title: i18n.basemaps.earthAtNight, + basemap: { + baseMapLayers: [ + { + url: 'https://tiles.arcgis.com/tiles/P3ePLMYs2RVChkJx/arcgis/rest/services/Earth_at_Night_WM/MapServer' + } + ] + } }, - hybrid: { - title: 'Hybrid' + davidRumseyMap1812: { + title: i18n.basemaps.davidRumseyMap1812, + basemap: { + baseMapLayers: [ + { + url: 'https://tiles.arcgis.com/tiles/IEuSomXfi6iB7a25/arcgis/rest/services/World_Globe_1812/MapServer' + } + ] + } + }, + mapboxPirates: { + title: 'Pirates (mapbox.com)', + basemap: new Basemap({ + id: 'mapboxPirates', + layers: [new BasemapLayer({ + url: 'https://${subDomain}.tiles.mapbox.com/v3/aj.Sketchy2/${level}/${col}/${row}.png', + copyright: 'mapbox, 2016', + id: 'mapboxPirates', + subDomains: ['a', 'b', 'c', 'd'], + type: 'WebTiledLayer' + })] + }) + } + + // additional examples of vector tile basemaps (requires v3.16 or higher) + /* + streetsVector: { + title: 'Streets', + basemap: { + baseMapLayers: [ + { + url: 'https://www.arcgis.com/sharing/rest/content/items/3b8814f6ddbd485cae67e8018992246e/resources/styles/root.json', + type: 'VectorTile' + } + ] + } + }, + satelliteVector: { + title: 'Satellite', + basemap: { + baseMapLayers: [ + { + url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer' + } + ] + } + }, + hybridVector: { + title: 'Hybrid', + basemap: { + baseMapLayers: [ + { + url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer' + }, + { + url: 'https://www.arcgis.com/sharing/rest/content/items/1854498c7e35420b963a514a32689c80/resources/styles/root.json', + type: 'VectorTile', + isReference: true + } + ] + } + }, + lightGrayVector: { + title: 'Light Gray Canvas', + basemap: { + baseMapLayers: [ + { + url: 'https://www.arcgis.com/sharing/rest/content/items/bdf1eec3fa79456c8c7c2bb62f86dade/resources/styles/root.json', + type: 'VectorTile' + } + ] + } }, - topo: { - title: 'Topo' + 'dark-gray-vector': { + title: 'Dark Gray Canvas', + basemap: { + baseMapLayers: [ + { + url: 'https://www.arcgis.com/sharing/rest/content/items/3e3099d7302f4d99bc6f916dcc07ed59/resources/styles/root.json', + type: 'VectorTile' + } + ] + } }, - gray: { - title: 'Gray' + navigationVector: { + title: 'Navigation', + basemap: { + baseMapLayers: [ + { + url: 'https://www.arcgis.com/sharing/rest/content/items/00cd8e843bae49b3a040423e5d65416b/resources/styles/root.json', + type: 'VectorTile' + } + ] + } }, - oceans: { - title: 'Oceans' + 'streets-night-vector': { + title: 'Streets Night', + basemap: { + baseMapLayers: [ + { + url: 'https://www.arcgis.com/sharing/rest/content/items/f96366254a564adda1dc468b447ed956/resources/styles/root.json', + type: 'VectorTile' + } + ] + } }, - 'national-geographic': { - title: 'Nat Geo' + streetsReliefVector: { + title: 'Streets w/ Relief', + basemap: { + baseMapLayers: [ + { + url: 'https://www.arcgis.com/sharing/rest/content/items/ad06088bd1174866aad2dddbf5ec9642/resources/styles/root.json', + type: 'VectorTile' + } + ] + } }, - osm: { - title: 'Open Street Map' + topoVector: { + title: 'Topographic', + basemap: { + baseMapLayers: [ + { + url: 'https://www.arcgis.com/sharing/rest/content/items/be44936bcdd24db588a1ae5076e36f34/resources/styles/root.json', + type: 'VectorTile' + } + ] + } } + */ - // examples of custom basemaps - - /*streets: { + //examples of custom basemaps + /* + streets: { title: 'Streets', basemap: new Basemap({ id: 'streets', layers: [new BasemapLayer({ - url: 'http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer' + url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer' })] }) }, @@ -55,7 +201,7 @@ define([ basemap: new Basemap({ id: 'satellite', layers: [new BasemapLayer({ - url: 'http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer' + url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer' })] }) }, @@ -64,13 +210,13 @@ define([ basemap: new Basemap({ id: 'hybrid', layers: [new BasemapLayer({ - url: 'http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer' + url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer' }), new BasemapLayer({ - url: 'http://services.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer', + url: 'https://services.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer', isReference: true, displayLevels: [0, 1, 2, 3, 4, 5, 6, 7] }), new BasemapLayer({ - url: 'http://services.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer', + url: 'https://services.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer', isReference: true, displayLevels: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] })] @@ -81,13 +227,50 @@ define([ basemap: new Basemap({ id: 'lightGray', layers: [new BasemapLayer({ - url: 'http://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer' + url: 'https://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer' }), new BasemapLayer({ - url: 'http://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Reference/MapServer', + url: 'https://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Reference/MapServer', isReference: true })] }) - }*/ + }, + stamenToner: { + title: 'Toner (maps.stamen.com)', + basemap: new Basemap({ + id: 'stamenToner', + layers: [new BasemapLayer({ + url: 'https://tile.stamen.com/toner/${level}/${col}/${row}.png', + copyright: 'stamen, 2016', + id: 'stamenToner', + type: 'WebTiledLayer' + })] + }) + }, + stamenTerrain: { + title: 'Terrain (stamen.com)', + basemap: new Basemap({ + id: 'stamenTerrain', + layers: [new BasemapLayer({ + url: 'https://tile.stamen.com/terrain/${level}/${col}/${row}.png', + copyright: 'stamen, 2016', + id: 'stamenTerrain', + type: 'WebTiledLayer' + })] + }) + }, + stamenWatercolor: { + title: 'Watercolor (stamen.com)', + basemap: new Basemap({ + id: 'stamenWatercolor', + layers: [new BasemapLayer({ + url: 'https://tile.stamen.com/watercolor/${level}/${col}/${row}.png', + copyright: 'stamen, 2016', + id: 'stamenWatercolor', + type: 'WebTiledLayer' + })] + }) + }, + */ } }; }); \ No newline at end of file diff --git a/viewer/js/config/bookmarks.js b/viewer/js/config/bookmarks.js index de9952abf..90beb5de4 100644 --- a/viewer/js/config/bookmarks.js +++ b/viewer/js/config/bookmarks.js @@ -1,18 +1,35 @@ -define({ - map: true, - editable: true, - bookmarks: [ - { - extent: { - xmin: -15489130.48708616, - ymin: 398794.4860580916, - xmax: -5891085.7193757, - ymax: 8509680.431452557, - spatialReference: { - wkid: 102100 - } - }, - name: 'USA' - } - ] +define([ + 'dojo/i18n!./nls/main' +], function (i18n) { + + return { + map: true, + editable: true, + bookmarks: [ + { + extent: { + xmin: -15489130.48708616, + ymin: 398794.4860580916, + xmax: -5891085.7193757, + ymax: 8509680.431452557, + spatialReference: { + wkid: 102100 + } + }, + name: i18n.bookmarks.usa + }, + { + extent: { + xmin: 0, + ymin: 0, + xmax: 0, + ymax: 0, + spatialReference: { + wkid: 102100 + } + }, + name: i18n.bookmarks.nullIsland + } + ] + }; }); \ No newline at end of file diff --git a/viewer/js/config/find.js b/viewer/js/config/find.js index 7e01c3e65..ad6bfb877 100644 --- a/viewer/js/config/find.js +++ b/viewer/js/config/find.js @@ -1,85 +1,117 @@ -define({ - map: true, - zoomExtentFactor: 2, - queries: [ - { - description: 'Find A Public Safety Location By Name', - url: 'http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/PublicSafety/PublicSafetyOperationalLayers/MapServer', - layerIds: [1, 2, 3, 4, 5, 6, 7], - searchFields: ['FDNAME, PDNAME', 'NAME', 'RESNAME'], - minChars: 2, - gridColumns: [ - { field: 'Name', label: 'Name' }, - { field: 'layerName', label: 'Layer', width: 100, sortable: false, resizable: false } - ], - sort: [ - { - attribute: 'Name', - descending: false - } - ], - prompt: 'fdname, pdname, name or resname', - selectionMode: 'single' - }, - { - description: 'Find Incident By Code/Description', - url: 'http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/PublicSafety/PublicSafetyOperationalLayers/MapServer', - layerIds: [15, 17, 18], - searchFields: ['FCODE', 'DESCRIPTION'], - minChars: 4, - gridColumns: [ - { field: 'layerName', label: 'Layer', width: 100, sortable: false, resizable: false }, - { field: 'Fcode', label: 'Fcode', width: 100 }, - { field: 'Description', label: 'Descr' }, - { field: 'SORT_VALUE', visible: false, get: function (findResult){ - return findResult.layerName + ' ' + findResult.feature.attributes.Fcode; //seems better to use attributes[ 'Fcode' ] but fails build. Attribute names will be aliases and may contain spaces and mixed cases. - } } - ], - sort: [ - { - attribute: 'SORT_VALUE', - descending: false - } - ], - prompt: 'fdname, pdname, name or resname', - customGridEventHandlers: [ - { - event: '.dgrid-row:click', - handler: function ( event ) { - alert( 'You clicked a row!' ); - console.log( event ); - } - } - ] - } - ], - selectionSymbols: { - polygon: { - type : 'esriSFS', - style : 'esriSFSSolid', - color : [255, 0, 0, 62], - outline: { - type : 'esriSLS', - style: 'esriSLSSolid', - color: [255, 0, 0, 255], - width: 3 - } - }, - point: { - type : 'esriSMS', - style : 'esriSMSCircle', - size : 25, - color : [255, 0, 0, 62], - angle : 0, - xoffset: 0, - yoffset: 0, - outline: { - type : 'esriSLS', - style: 'esriSLSSolid', - color: [255, 0, 0, 255], - width: 2 - } - } - }, - selectionMode : 'extended' +/*eslint no-console: 0, no-alert: 0*/ +define([ + 'dojo/i18n!./nls/main' +], function (i18n) { + + return { + map: true, + zoomExtentFactor: 2, + queries: [ + { + description: i18n.find.louisvillePubSafety, + url: 'https://sampleserver1.arcgisonline.com/ArcGIS/rest/services/PublicSafety/PublicSafetyOperationalLayers/MapServer', + layerIds: [1, 2, 3, 4, 5, 6, 7], + searchFields: ['FDNAME, PDNAME', 'NAME', 'RESNAME'], + minChars: 2, + gridColumns: [ + { + field: 'Name', + label: 'Name' + }, + { + field: 'layerName', + label: 'Layer', + width: 100, + sortable: false, + resizable: false + } + ], + sort: [ + { + attribute: 'Name', + descending: false + } + ], + prompt: 'fdname, pdname, name or resname', + selectionMode: 'single' + }, + { + description: i18n.find.sf311Incidents, + url: 'https://sampleserver1.arcgisonline.com/ArcGIS/rest/services/PublicSafety/PublicSafetyOperationalLayers/MapServer', + layerIds: [15, 17, 18], + searchFields: ['FCODE', 'DESCRIPTION'], + minChars: 4, + gridColumns: [ + { + field: 'layerName', + label: 'Layer', + width: 100, + sortable: false, + resizable: false + }, + { + field: 'Fcode', + label: 'Fcode', + width: 100 + }, + { + field: 'Description', + label: 'Descr' + }, + { + field: 'SORT_VALUE', + visible: false, + get: function (findResult) { + return findResult.layerName + ' ' + findResult.feature.attributes.Fcode; //seems better to use attributes[ 'Fcode' ] but fails build. Attribute names will be aliases and may contain spaces and mixed cases. + } + } + ], + sort: [ + { + attribute: 'SORT_VALUE', + descending: false + } + ], + prompt: 'fdname, pdname, name or resname', + customGridEventHandlers: [ + { + event: '.dgrid-row:click', + handler: function (event) { + alert('You clicked a row!'); + console.log(event); + } + } + ] + } + ], + selectionSymbols: { + polygon: { + type: 'esriSFS', + style: 'esriSFSSolid', + color: [255, 0, 0, 62], + outline: { + type: 'esriSLS', + style: 'esriSLSSolid', + color: [255, 0, 0, 255], + width: 3 + } + }, + point: { + type: 'esriSMS', + style: 'esriSMSCircle', + size: 25, + color: [255, 0, 0, 62], + angle: 0, + xoffset: 0, + yoffset: 0, + outline: { + type: 'esriSLS', + style: 'esriSLSSolid', + color: [255, 0, 0, 255], + width: 2 + } + } + }, + selectionMode: 'extended' + }; }); \ No newline at end of file diff --git a/viewer/js/config/identify.js b/viewer/js/config/identify.js index 2baefba3e..a85fb35b1 100644 --- a/viewer/js/config/identify.js +++ b/viewer/js/config/identify.js @@ -1,68 +1,80 @@ -define({ - map: true, - mapClickMode: true, - mapRightClickMenu: true, - identifyLayerInfos: true, - identifyTolerance: 5, +define([ + 'dojo/i18n!./nls/main', + 'dojo/_base/lang' +], function (i18n, lang) { - // config object definition: - // {:{ - // :{ - // - // } - // }, - // :{ - // :{ - // - // } - // } - // } + var linkTemplate = '{text}'; + function directionsFormatter (noValue, attributes) { + return lang.replace(linkTemplate, { + url: 'https://www.google.com/maps/dir/' + attributes.Address + ' Louisville, KY', + text: 'Get Directions' + }); + } + return { + map: true, + mapClickMode: true, + mapRightClickMenu: true, + identifyLayerInfos: true, + identifyTolerance: 5, + draggable: false, - // for details on pop-up definition see: https://developers.arcgis.com/javascript/jshelp/intro_popuptemplate.html + // config object definition: + // {:{ + // :{ + // + // } + // }, + // :{ + // :{ + // + // } + // } + // } - identifies: { - meetupHometowns: { - 0: { - title: 'Hometowns', - fieldInfos: [{ - fieldName: 'Location', - visible: true - }] - } - }, - louisvillePubSafety: { - 2: { - title: 'Police Station', - fieldInfos: [{ - fieldName: 'Name', - visible: true - }, { - fieldName: 'Address', - visible: true - }, { - fieldName: 'Type', - visible: true - }, { - fieldName: 'Police Function', - visible: true - }, { - fieldName: 'Last Update Date', - visible: true - }] - }, - 8: { - title: 'Traffic Camera', - description: '{Description} lasted updated: {Last Update Date}', - mediaInfos: [{ - title: '', - caption: '', - type: 'image', - value: { - sourceURL: '{Location URL}', - linkURL: '{Location URL}' - } - }] - } - } - } -}); \ No newline at end of file + // for details on pop-up definition see: https://developers.arcgis.com/javascript/jshelp/intro_popuptemplate.html + + identifies: { + louisvillePubSafety: { + 2: { + title: i18n.identify.louisvillePubSafety.policeStation, + fieldInfos: [{ + // example of adding a 'calculated' or formatted field + // click on a louisville kentucky police station to see + // the result + fieldName: 'Directions', + visible: true, + formatter: directionsFormatter + }, { + fieldName: 'Name', + visible: true + }, { + fieldName: 'Address', + visible: true + }, { + fieldName: 'Type', + visible: true + }, { + fieldName: 'Police Function', + visible: true + }, { + fieldName: 'Last Update Date', + visible: true + }] + }, + 8: { + title: i18n.identify.louisvillePubSafety.trafficCamera, + description: '{Description} lasted updated: {Last Update Date}', + mediaInfos: [{ + title: '', + caption: '', + type: 'image', + value: { + sourceURL: '{Location URL}', + linkURL: '{Location URL}' + } + }] + } + } + } + }; +}); diff --git a/viewer/js/config/nls/es/main.js b/viewer/js/config/nls/es/main.js new file mode 100644 index 000000000..47acf6117 --- /dev/null +++ b/viewer/js/config/nls/es/main.js @@ -0,0 +1,50 @@ +// http://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html +define({ + basemaps: { + davidRumseyMap1812: 'David Rumsey 1812', + earthAtNight: 'Tierra en la noche', + landsatShaded: 'Landsat sombreada' + }, + bookmarks: { + nullIsland: 'Isla nula', + usa: 'EE.UU.' + }, + find: { + louisvillePubSafety: 'Encontrar un local de Seguridad Pública por su nombre', + sf311Incidents: 'Encuentra incidente por código/descripción' + }, + identify: { + louisvillePubSafety: { + policeStation: 'Comisaría de Policía', + trafficCamera: 'Cámara de Tráfico' + } + }, + viewer: { + operationalLayers: { + damageAssessment: 'Valoración de daño', + louisvillePubSafety: 'Seguridad Pública de Louisville', + restaurants: 'Restaurantes', + sf311Incidents: '311 Incidentes de San Francisco' + }, + titles: { + header: 'Configurable Map Viewer', + pageTitle: 'Configurable Map Viewer — Un visor de mapas configurables', // One configurable map viewer + subHeader: 'personalizarlo a su gusto' // customize it at your will (the literal translation doesn’t sound good) + }, + widgets: { + bookmarks: 'Marcadores', + directions: 'Direcciones', + draw: 'Dibujar', + editor: 'Editor', + find: 'Encontrar', + help: 'Ayuda', + identify: 'Identificar', + measure: 'Medición', + layerControl: 'Capas', + legend: 'Leyenda', + locale: 'Lugar', + print: 'Imprimir', + streetview: 'Google Street View' + } + } +}); \ No newline at end of file diff --git a/viewer/js/config/nls/fr/main.js b/viewer/js/config/nls/fr/main.js new file mode 100644 index 000000000..dbf7b877d --- /dev/null +++ b/viewer/js/config/nls/fr/main.js @@ -0,0 +1,50 @@ +// http://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html +define({ + basemaps: { + davidRumseyMap1812: 'David Rumsey 1812', + earthAtNight: 'Terre la nuit', + landsatShaded: 'Landsat et relief ombragé' + }, + bookmarks: { + nullIsland: 'Île Null', + usa: 'États-Unis' + }, + find: { + louisvillePubSafety: 'Trouvez un bâtiment de sécurité publique par nom', + sf311Incidents: 'Trouver un incident par code/description' + }, + identify: { + louisvillePubSafety: { + policeStation: 'Poste de police', + trafficCamera: 'Caméra de circulation' + } + }, + viewer: { + operationalLayers: { + damageAssessment: 'Évaluation des dommages', + louisvillePubSafety: 'Sécurité publique de Louisville', + restaurants: 'Restaurants', + sf311Incidents: 'Incidents 311 de San Francisco' + }, + titles: { + header: 'Configurable Map Viewer', + pageTitle: 'Configurable Map Viewer - Un visualiseur de cartes configurables', + subHeader: 'Personnalisez-le' + }, + widgets: { + bookmarks: 'Géosignets', + directions: 'Directions', + draw: 'Annotations', + editor: 'Éditeur', + find: 'Rechercher', + help: 'Aide', + identify: 'Identifier', + measure: 'Mesures', + layerControl: 'Couches d\'information', + legend: 'Légende', + locale: 'Lieu', + print: 'Impression', + streetview: 'Google StreetView' + } + } +}); diff --git a/viewer/js/config/nls/main.js b/viewer/js/config/nls/main.js new file mode 100644 index 000000000..d4e18302b --- /dev/null +++ b/viewer/js/config/nls/main.js @@ -0,0 +1,56 @@ +// http://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html +define({ + root: { + basemaps: { + davidRumseyMap1812: 'David Rumsey 1812', + earthAtNight: 'Earth at Night', + landsatShaded: 'Landsat Shaded' + }, + bookmarks: { + nullIsland: 'Null Island', + usa: 'USA' + }, + find: { + louisvillePubSafety: 'Find A Public Safety Location By Name', + sf311Incidents: 'Find Incident By Code/Description' + }, + identify: { + louisvillePubSafety: { + policeStation: 'Police Station', + trafficCamera: 'Traffic Camera' + } + }, + viewer: { + operationalLayers: { + damageAssessment: 'Damage Assessment', + louisvillePubSafety: 'Louisville Public Safety', + restaurants: 'Restaurants', + sf311Incidents: 'San Francisco 311 Incidents' + }, + titles: { + header: 'Configurable Map Viewer', + pageTitle: 'Configurable Map Viewer', + subHeader: 'make it your own' + }, + widgets: { + bookmarks: 'Bookmarks', + directions: 'Directions', + draw: 'Draw', + editor: 'Editor', + find: 'Find', + help: 'Help', + identify: 'Identify', + measure: 'Measurement', + layerControl: 'Layers', + legend: 'Legend', + locale: 'Locale', + print: 'Print', + streetview: 'Google Street View' + } + } + }, + 'es': true, + 'fr': true, + 'pt-br': true, + 'pt-pt': true +}); diff --git a/viewer/js/config/nls/pt-br/main.js b/viewer/js/config/nls/pt-br/main.js new file mode 100644 index 000000000..3bb82f665 --- /dev/null +++ b/viewer/js/config/nls/pt-br/main.js @@ -0,0 +1,50 @@ +// http://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html +define({ + basemaps: { + davidRumseyMap1812: 'David Rumsey 1812', + earthAtNight: 'Terra à noite', + landsatShaded: 'Landsat sombreado' + }, + bookmarks: { + nullIsland: 'Ilha Nula', + usa: 'EUA' + }, + find: { + louisvillePubSafety: 'Encontrar um local de Segurança Pública pelo nome', + sf311Incidents: 'Encontrar incidente por código/descrição' + }, + identify: { + louisvillePubSafety: { + policeStation: 'Esquadra da Polícia', + trafficCamera: 'Câmara de trânsito' + } + }, + viewer: { + operationalLayers: { + damageAssessment: 'Avaliação de dano', + louisvillePubSafety: 'Segurança Pública de Louisville', + restaurants: 'Restaurantes', + sf311Incidents: 'Incidentes do 311 de São Francisco' + }, + titles: { + header: 'Configurable Map Viewer', + pageTitle: 'Configurable Map Viewer — Um visualizador de mapas configurável', // One configurable map viewer + subHeader: 'personaliza-o ao teu gosto' // customize it at your will (the literal translation doesn’t sound good) + }, + widgets: { + bookmarks: 'Marcadores', + directions: 'Direcções', + draw: 'Desenhar', + editor: 'Editor', + find: 'Procurar', + help: 'Ajuda', + identify: 'Identificar', + measure: 'Medir', + layerControl: 'Camadas', + legend: 'Legendas', + locale: 'Localidade', + print: 'Imprimir', + streetview: 'Google Street View' + } + } +}); diff --git a/viewer/js/config/nls/pt-pt/main.js b/viewer/js/config/nls/pt-pt/main.js new file mode 100644 index 000000000..3bb82f665 --- /dev/null +++ b/viewer/js/config/nls/pt-pt/main.js @@ -0,0 +1,50 @@ +// http://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html +define({ + basemaps: { + davidRumseyMap1812: 'David Rumsey 1812', + earthAtNight: 'Terra à noite', + landsatShaded: 'Landsat sombreado' + }, + bookmarks: { + nullIsland: 'Ilha Nula', + usa: 'EUA' + }, + find: { + louisvillePubSafety: 'Encontrar um local de Segurança Pública pelo nome', + sf311Incidents: 'Encontrar incidente por código/descrição' + }, + identify: { + louisvillePubSafety: { + policeStation: 'Esquadra da Polícia', + trafficCamera: 'Câmara de trânsito' + } + }, + viewer: { + operationalLayers: { + damageAssessment: 'Avaliação de dano', + louisvillePubSafety: 'Segurança Pública de Louisville', + restaurants: 'Restaurantes', + sf311Incidents: 'Incidentes do 311 de São Francisco' + }, + titles: { + header: 'Configurable Map Viewer', + pageTitle: 'Configurable Map Viewer — Um visualizador de mapas configurável', // One configurable map viewer + subHeader: 'personaliza-o ao teu gosto' // customize it at your will (the literal translation doesn’t sound good) + }, + widgets: { + bookmarks: 'Marcadores', + directions: 'Direcções', + draw: 'Desenhar', + editor: 'Editor', + find: 'Procurar', + help: 'Ajuda', + identify: 'Identificar', + measure: 'Medir', + layerControl: 'Camadas', + legend: 'Legendas', + locale: 'Localidade', + print: 'Imprimir', + streetview: 'Google Street View' + } + } +}); diff --git a/viewer/js/config/viewer.js b/viewer/js/config/viewer.js index 8067cb55e..d11dc7490 100644 --- a/viewer/js/config/viewer.js +++ b/viewer/js/config/viewer.js @@ -1,20 +1,72 @@ define([ - 'esri/units', - 'esri/geometry/Extent', - 'esri/config', - 'esri/tasks/GeometryService', - 'esri/layers/ImageParameters' -], function (units, Extent, esriConfig, GeometryService, ImageParameters) { + 'esri/units', + 'esri/geometry/Extent', + 'esri/config', + /*'esri/urlUtils',*/ + 'esri/tasks/GeometryService', + 'esri/layers/ImageParameters', + 'gis/plugins/Google', + 'dojo/i18n!./nls/main', + 'dojo/topic' +], function (units, Extent, esriConfig, /*urlUtils,*/ GeometryService, ImageParameters, GoogleMapsLoader, i18n, topic) { // url to your proxy page, must be on same machine hosting you app. See proxy folder for readme. esriConfig.defaults.io.proxyUrl = 'proxy/proxy.ashx'; esriConfig.defaults.io.alwaysUseProxy = false; + + // add a proxy rule to force specific domain requests through proxy + // be sure the domain is added in proxy.config + /*urlUtils.addProxyRule({ + urlPrefix: 'www.example.com', + proxyUrl: 'proxy/proxy.ashx' + });*/ + // url to your geometry server. - esriConfig.defaults.geometryService = new GeometryService('http://tasks.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer'); + esriConfig.defaults.geometryService = new GeometryService('https://tasks.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer'); + + // Use your own Google Maps API Key. + // https://developers.google.com/maps/documentation/javascript/get-api-key + GoogleMapsLoader.KEY = 'NOT-A-REAL-API-KEY'; + + // helper function returning ImageParameters for dynamic layers + // example: + // imageParameters: buildImageParameters({ + // layerIds: [0], + // layerOption: 'show' + // }) + function buildImageParameters (config) { + config = config || {}; + var ip = new ImageParameters(); + //image parameters for dynamic services, set to png32 for higher quality exports + ip.format = 'png32'; + for (var key in config) { + if (config.hasOwnProperty(key)) { + ip[key] = config[key]; + } + } + return ip; + } - //image parameters for dynamic services, set to png32 for higher quality exports. - var imageParameters = new ImageParameters(); - imageParameters.format = 'png32'; + //some example topics for listening to menu item clicks + //these topics publish a simple message to the growler + //in a real world example, these topics would be used + //in their own widget to listen for layer menu click events + topic.subscribe('layerControl/hello', function (event) { + topic.publish('growler/growl', { + title: 'Hello!', + message: event.layer._titleForLegend + ' ' + + (event.subLayer ? event.subLayer.name : '') + + ' says hello' + }); + }); + topic.subscribe('layerControl/goodbye', function (event) { + topic.publish('growler/growl', { + title: 'Goodbye!', + message: event.layer._titleForLegend + ' ' + + (event.subLayer ? event.subLayer.name : '') + + ' says goodbye' + }); + }); return { // used for debugging your app @@ -29,6 +81,10 @@ define([ zoom: 5, sliderStyle: 'small' }, + + //webMapId: 'ef9c7fbda731474d98647bebb4b33c20', // High Cost Mortgage + // webMapOptions: {}, + // panes: { // left: { // splitter: true @@ -57,15 +113,36 @@ define([ // }, // collapseButtonsPane: 'center', //center or outer + // custom titles + titles: { + header: i18n.viewer.titles.header, + subHeader: i18n.viewer.titles.subHeader, + pageTitle: i18n.viewer.titles.pageTitle + }, + + // user-defined layer types + /* + layerTypes: { + myCustomLayer: 'widgets/MyCustomLayer' + }, + */ + + // user-defined widget types + /* + widgetTypes: [ + 'myWidgetType' + ], + */ + // operationalLayers: Array of Layers to load on top of the basemap: valid 'type' options: 'dynamic', 'tiled', 'feature'. // The 'options' object is passed as the layers options for constructor. Title will be used in the legend only. id's must be unique and have no spaces. // 3 'mode' options: MODE_SNAPSHOT = 0, MODE_ONDEMAND = 1, MODE_SELECTION = 2 operationalLayers: [{ type: 'feature', - url: 'http://services1.arcgis.com/g2TonOxuRkIqSOFx/arcgis/rest/services/MeetUpHomeTowns/FeatureServer/0', - title: 'STLJS Meetup Home Towns', + url: 'https://services1.arcgis.com/6bXbLtkf4y11TosO/arcgis/rest/services/Restaurants/FeatureServer/0', + title: i18n.viewer.operationalLayers.restaurants, options: { - id: 'meetupHometowns', + id: 'restaurants', opacity: 1.0, visible: true, outFields: ['*'], @@ -77,47 +154,60 @@ define([ legendLayerInfos: { exclude: false, layerInfo: { - title: 'My layer' + title: i18n.viewer.operationalLayers.restaurants } } - }, { + }, { type: 'feature', - url: 'http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/FeatureServer/0', - title: 'San Francisco 311 Incidents', + url: 'https://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/FeatureServer/0', + title: i18n.viewer.operationalLayers.sf311Incidents, options: { id: 'sf311Incidents', opacity: 1.0, visible: true, outFields: ['req_type', 'req_date', 'req_time', 'address', 'district'], mode: 0 + }, + layerControlLayerInfos: { + menu: [{ + topic: 'hello', + label: 'Say Hello Custom', + iconClass: 'fa fa-smile-o' + }] } - }, { + }, { type: 'dynamic', - url: 'http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/PublicSafety/PublicSafetyOperationalLayers/MapServer', - title: 'Louisville Public Safety', + url: 'https://sampleserver1.arcgisonline.com/ArcGIS/rest/services/PublicSafety/PublicSafetyOperationalLayers/MapServer', + title: i18n.viewer.operationalLayers.louisvillePubSafety, options: { id: 'louisvillePubSafety', opacity: 1.0, visible: true, - imageParameters: imageParameters + imageParameters: buildImageParameters({ + layerIds: [0, 2, 4, 5, 8, 10, 12, 21], + layerOption: 'show' + }) }, identifyLayerInfos: { layerIds: [2, 4, 5, 8, 12, 21] }, + layerControlLayerInfos: { + layerIds: [0, 2, 4, 5, 8, 9, 10, 12, 21] + }, legendLayerInfos: { layerInfo: { hideLayers: [21] } } - }, { + }, { type: 'dynamic', - url: 'http://sampleserver6.arcgisonline.com/arcgis/rest/services/DamageAssessment/MapServer', - title: 'Damage Assessment', + url: 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/DamageAssessment/MapServer', + title: i18n.viewer.operationalLayers.damageAssessment, options: { - id: 'DamageAssessment', + id: 'damageAssessment', opacity: 1.0, visible: true, - imageParameters: imageParameters + imageParameters: buildImageParameters() }, legendLayerInfos: { exclude: true @@ -125,9 +215,73 @@ define([ layerControlLayerInfos: { swipe: true, metadataUrl: true, - expanded: true + expanded: true, + + //override the menu on this particular layer + subLayerMenu: [{ + topic: 'hello', + label: 'Say Hello', + iconClass: 'fa fa-smile-o' + }] + } + /* + //examples of vector tile layers (beta in v3.15) + }, { + type: 'vectortile', + title: 'Light Gray Canvas Vector', + url: 'https//www.arcgis.com/sharing/rest/content/items/bdf1eec3fa79456c8c7c2bb62f86dade/resources/styles/root.json', + options: { + id: 'vectortile1', + opacity: 0.8, + visible: true + } + }, { + // taken from this demo: https://github.com/ycabon/presentations/blob/gh-pages/2015-berlin-plenary/demos/3.15-vectortile/create-by-style-object.html + type: 'vectortile', + title: 'Custom Vector Style', + options: { + id: 'vectortile2', + opacity: 1.0, + visible: true, + 'glyphs': 'https://www.arcgis.com/sharing/rest/content/items/00cd8e843bae49b3a040423e5d65416b/resources/fonts/{fontstack}/{range}.pbf', + 'sprite': 'https://www.arcgis.com/sharing/rest/content/items/00cd8e843bae49b3a040423e5d65416b/resources/sprites/sprite', + 'version': 8, + 'sources': { + 'esri': { + 'url': 'https://basemapsdev.arcgis.com/arcgis/rest/services/World_Basemap/VectorTileServer', + 'type': 'vector' + } + }, + 'layers': [{ + 'id': 'background', + 'type': 'background', + 'paint': { + 'background-color': '#556688' + } + }, { + 'id': 'Land', + 'type': 'fill', + 'source': 'esri', + 'source-layer': 'Land', + 'paint': { + 'fill-color': '#273344' + }, + }, { + 'id': 'roads', + 'type': 'line', + 'source': 'esri', + 'source-layer': 'Road', + 'layout': { + 'line-join': 'round' + }, + 'paint': { + 'line-width': 1, + 'line-color': '#131622' + } + }] } - }], + */ + }], // set include:true to load. For titlePane type set position the the desired order in the sidebar widgets: { growler: { @@ -138,41 +292,38 @@ define([ srcNodeRef: 'growlerDijit', options: {} }, - geocoder: { + search: { include: true, - id: 'geocoder', type: 'domNode', - path: 'gis/dijit/Geocoder', - srcNodeRef: 'geocodeDijit', + path: 'esri/dijit/Search', + srcNodeRef: 'geocoderButton', options: { map: true, - mapRightClickMenu: true, - geocoderOptions: { - autoComplete: true, - arcgisGeocoder: { - placeholder: 'Enter an address or place' - } - } + visible: true, + enableInfoWindow: false, + enableButtonMode: true, + expanded: false } }, + basemaps: { + include: true, + id: 'basemaps', + type: 'domNode', + path: 'gis/dijit/Basemaps', + srcNodeRef: 'basemapsDijit', + options: 'config/basemaps' + }, identify: { include: true, id: 'identify', type: 'titlePane', path: 'gis/dijit/Identify', - title: 'Identify', + title: i18n.viewer.widgets.identify, + iconClass: 'fa-info-circle', open: false, position: 3, options: 'config/identify' }, - basemaps: { - include: true, - id: 'basemaps', - type: 'domNode', - path: 'gis/dijit/Basemaps', - srcNodeRef: 'basemapsDijit', - options: 'config/basemaps' - }, mapInfo: { include: false, id: 'mapInfo', @@ -258,10 +409,11 @@ define([ include: true, id: 'legend', type: 'titlePane', - path: 'esri/dijit/Legend', - title: 'Legend', + path: 'gis/dijit/Legend', + title: i18n.viewer.widgets.legend, + iconClass: 'fa-picture-o', open: false, - position: 0, + position: 1, options: { map: true, legendLayerInfos: true @@ -272,7 +424,8 @@ define([ id: 'layerControl', type: 'titlePane', path: 'gis/dijit/LayerControl', - title: 'Layers', + title: i18n.viewer.widgets.layerControl, + iconClass: 'fa-th-list', open: false, position: 0, options: { @@ -280,7 +433,25 @@ define([ layerControlLayerInfos: true, separated: true, vectorReorder: true, - overlayReorder: true + overlayReorder: true, + // create a custom menu entry in all of these feature types + // the custom menu item will publish a topic when clicked + menu: { + feature: [{ + topic: 'hello', + iconClass: 'fa fa-smile-o', + label: 'Say Hello' + }] + }, + //create a example sub layer menu that will + //apply to all layers of type 'dynamic' + subLayerMenu: { + dynamic: [{ + topic: 'goodbye', + iconClass: 'fa fa-frown-o', + label: 'Say goodbye' + }] + } } }, bookmarks: { @@ -288,7 +459,8 @@ define([ id: 'bookmarks', type: 'titlePane', path: 'gis/dijit/Bookmarks', - title: 'Bookmarks', + title: i18n.viewer.widgets.bookmarks, + iconClass: 'fa-bookmark', open: false, position: 2, options: 'config/bookmarks' @@ -299,7 +471,8 @@ define([ type: 'titlePane', canFloat: true, path: 'gis/dijit/Find', - title: 'Find', + title: i18n.viewer.widgets.find, + iconClass: 'fa-search', open: false, position: 3, options: 'config/find' @@ -310,7 +483,8 @@ define([ type: 'titlePane', canFloat: true, path: 'gis/dijit/Draw', - title: 'Draw', + title: i18n.viewer.widgets.draw, + iconClass: 'fa-paint-brush', open: false, position: 4, options: { @@ -324,7 +498,8 @@ define([ type: 'titlePane', canFloat: true, path: 'gis/dijit/Measurement', - title: 'Measurement', + title: i18n.viewer.widgets.measure, + iconClass: 'fa-expand', open: false, position: 5, options: { @@ -340,7 +515,8 @@ define([ type: 'titlePane', canFloat: true, path: 'gis/dijit/Print', - title: 'Print', + title: i18n.viewer.widgets.print, + iconClass: 'fa-print', open: false, position: 6, options: { @@ -358,14 +534,15 @@ define([ id: 'directions', type: 'titlePane', path: 'gis/dijit/Directions', - title: 'Directions', + title: i18n.viewer.widgets.directions, + iconClass: 'fa-map-signs', open: false, position: 7, options: { map: true, mapRightClickMenu: true, options: { - routeTaskUrl: 'http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Network/USA/NAServer/Route', + routeTaskUrl: 'https://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Network/USA/NAServer/Route', routeParams: { directionsLanguage: 'en-US', directionsLengthUnits: units.MILES @@ -379,7 +556,8 @@ define([ id: 'editor', type: 'titlePane', path: 'gis/dijit/Editor', - title: 'Editor', + title: i18n.viewer.widgets.editor, + iconClass: 'fa-pencil', open: false, position: 8, options: { @@ -408,22 +586,46 @@ define([ canFloat: true, position: 9, path: 'gis/dijit/StreetView', - title: 'Google Street View', + title: i18n.viewer.widgets.streetview, + iconClass: 'fa-street-view', + paneOptions: { + resizable: true, + resizeOptions: { + minSize: { + w: 250, + h: 250 + } + } + }, options: { map: true, mapClickMode: true, mapRightClickMenu: true } }, + locale: { + include: true, + id: 'locale', + //type: 'titlePane', + //position: 0, + //open: true, + type: 'domNode', + srcNodeRef: 'geocodeDijit', + path: 'gis/dijit/Locale', + title: i18n.viewer.widgets.locale, + options: { + style: 'margin-left: 30px;' + } + }, help: { include: true, id: 'help', type: 'floating', path: 'gis/dijit/Help', - title: 'Help', + title: i18n.viewer.widgets.help, options: {} } } }; -}); \ No newline at end of file +}); diff --git a/viewer/js/gis/dijit/BasemapGallery.js b/viewer/js/gis/dijit/BasemapGallery.js new file mode 100644 index 000000000..9b0c5b31a --- /dev/null +++ b/viewer/js/gis/dijit/BasemapGallery.js @@ -0,0 +1,65 @@ +define([ + 'dojo/_base/declare', + 'dijit/_WidgetBase', + 'dijit/_TemplatedMixin', + 'dijit/_WidgetsInTemplateMixin', + + 'dojo/_base/lang', + 'dojo/topic', + + 'esri/dijit/BasemapGallery', + + 'dojo/text!./BasemapGallery/templates/BasemapGallery.html', + 'dojo/i18n!./BasemapGallery/nls/resource', + + 'dijit/layout/ContentPane', + 'dijit/TitlePane', + + 'xstyle/css!./BasemapGallery/css/BasemapGallery.css' + +], function ( + declare, + _WidgetBase, + _TemplatedMixin, + _WidgetsInTemplateMixin, + + lang, + topic, + + BasemapGallery, + + template, + i18n +) { + + return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], { + widgetsInTemplate: true, + templateString: template, + i18n: i18n, + baseClass: 'cmvBasemapGalleryWidget', + + galleryOptions: { + showArcGISBasemaps: true + }, + + postCreate: function () { + this.inherited(arguments); + + var opts = lang.mixin({ + map: this.map + }, this.galleryOptions || {}); + this.basemapGallery = new BasemapGallery(opts, 'basemapGallery'); + this.basemapGallery.startup(); + + this.basemapGallery.on('selection-change', lang.hitch(this, 'basemapSelected')); + + this.basemapGallery.on('error', function (msg) { + topic.publish('viewer/handleError', 'basemap gallery error: ' + msg); + }); + }, + + basemapSelected: function (/* basemap */) { + this.basemapGalleryTitlePane.set('open', false); + } + }); +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/BasemapGallery/css/BasemapGallery.css b/viewer/js/gis/dijit/BasemapGallery/css/BasemapGallery.css new file mode 100644 index 000000000..4bb99ef2b --- /dev/null +++ b/viewer/js/gis/dijit/BasemapGallery/css/BasemapGallery.css @@ -0,0 +1,41 @@ +.cmvBasemapGalleryWidget .dijitTitlePane { + border-radius: 4px; +} + +.cmvBasemapGalleryWidget .dijitTitlePaneTitle { + border-color: #BBB; + padding: 4px; +} + +.cmvBasemapGalleryWidget .dijitTitlePane .dijitArrowNode { + float: right; + padding-top: 3px; +} + +.cmvBasemapGalleryWidget .dijitTitlePaneTextNode:before { + content: '\f009'; + font-family: FontAwesome; +} + +.cmvBasemapGalleryWidget .dijitTitlePaneContentOuter { + border-color: #BBB; +} + +.cmvBasemapGalleryWidget .dijitTitlePaneContentInner { + padding: 0; +} + +.cmvBasemapGalleryWidget .basemapGalleryContent { + height: 280px; + overflow:auto; + width: 410px; +} +.cmvBasemapGalleryWidget .esriBasemapGalleryNode { + margin: 5px 15px; +} + +@media screen and (max-width: 767px) { + .cmvBasemapGalleryWidget .basemapGalleryContent { + width: 140px; + } +} \ No newline at end of file diff --git a/viewer/js/gis/dijit/BasemapGallery/nls/es/resource.js b/viewer/js/gis/dijit/BasemapGallery/nls/es/resource.js new file mode 100644 index 000000000..48f8546d9 --- /dev/null +++ b/viewer/js/gis/dijit/BasemapGallery/nls/es/resource.js @@ -0,0 +1,3 @@ +define ({ + title: 'Mapas base' +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/BasemapGallery/nls/fr/resource.js b/viewer/js/gis/dijit/BasemapGallery/nls/fr/resource.js new file mode 100644 index 000000000..1717b565f --- /dev/null +++ b/viewer/js/gis/dijit/BasemapGallery/nls/fr/resource.js @@ -0,0 +1,3 @@ +define ({ + title: 'Fond de carte' +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/BasemapGallery/nls/pt-br/resource.js b/viewer/js/gis/dijit/BasemapGallery/nls/pt-br/resource.js new file mode 100644 index 000000000..48f8546d9 --- /dev/null +++ b/viewer/js/gis/dijit/BasemapGallery/nls/pt-br/resource.js @@ -0,0 +1,3 @@ +define ({ + title: 'Mapas base' +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/BasemapGallery/nls/pt-pt/resource.js b/viewer/js/gis/dijit/BasemapGallery/nls/pt-pt/resource.js new file mode 100644 index 000000000..d67f99c97 --- /dev/null +++ b/viewer/js/gis/dijit/BasemapGallery/nls/pt-pt/resource.js @@ -0,0 +1,3 @@ +define({ + title: 'Mapas base' +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/BasemapGallery/nls/resource.js b/viewer/js/gis/dijit/BasemapGallery/nls/resource.js new file mode 100644 index 000000000..99c7c0fae --- /dev/null +++ b/viewer/js/gis/dijit/BasemapGallery/nls/resource.js @@ -0,0 +1,9 @@ +define ({ + root: { + title: 'Basemaps' + }, + 'es': true, + 'fr': true, + 'pt-br': true, + 'pt-pt': true +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/BasemapGallery/templates/BasemapGallery.html b/viewer/js/gis/dijit/BasemapGallery/templates/BasemapGallery.html new file mode 100644 index 000000000..26ea418e5 --- /dev/null +++ b/viewer/js/gis/dijit/BasemapGallery/templates/BasemapGallery.html @@ -0,0 +1,7 @@ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/viewer/js/gis/dijit/Basemaps.js b/viewer/js/gis/dijit/Basemaps.js index 12cfc45ad..72a9dbbce 100644 --- a/viewer/js/gis/dijit/Basemaps.js +++ b/viewer/js/gis/dijit/Basemaps.js @@ -3,98 +3,174 @@ define([ 'dijit/_WidgetBase', 'dijit/_TemplatedMixin', 'dijit/_WidgetsInTemplateMixin', + 'dojo/_base/lang', + 'dojo/_base/array', + 'dojo/topic', + 'dijit/DropDownMenu', 'dijit/MenuItem', - 'dojo/_base/array', - 'dojox/lang/functional', - 'dojo/text!./Basemaps/templates/Basemaps.html', + + 'esri/basemaps', 'esri/dijit/BasemapGallery', + + 'dojo/text!./Basemaps/templates/Basemaps.html', 'dojo/i18n!./Basemaps/nls/resource', 'dijit/form/DropDownButton', 'xstyle/css!./Basemaps/css/Basemaps.css' -], function (declare, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, lang, DropDownMenu, MenuItem, array, functional, template, BasemapGallery, i18n) { +], function ( + declare, + _WidgetBase, + _TemplatedMixin, + _WidgetsInTemplateMixin, + + lang, + array, + topic, + + DropDownMenu, + MenuItem, + + esriBasemaps, + BasemapGallery, + + template, + i18n +) { - // main basemap widget return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], { templateString: template, widgetsInTemplate: true, i18n: i18n, - mode: 'agol', title: i18n.title, - //baseClass: 'gis_Basemaps_Dijit', - //buttonClass: 'gis_Basemaps_Button', - //menuClass: 'gis_Basemaps_Menu', - mapStartBasemap: 'streets', - basemapsToShow: ['streets', 'satellite', 'hybrid', 'topo', 'gray', 'oceans', 'national-geographic', 'osm'], - validBasemaps: [], + + basemaps: {}, + currentBasemap: null, + mapStartBasemap: null, + basemapsToShow: null, + galleryOptions: { + basemapIds: null, + basemaps: null, + basemapsGroup: null, + bingMapsKey: null, + portalUrl: null, + referenceIds: null, + showArcGISBasemaps: false + }, + postCreate: function () { this.inherited(arguments); - this.currentBasemap = this.mapStartBasemap || null; - - if (this.mode === 'custom') { - this.gallery = new BasemapGallery({ - map: this.map, - showArcGISBasemaps: false, - basemaps: functional.map(this.basemaps, function (map) { - return map.basemap; - }) + this.initializeBasemaps(); + this.createBasemapGallery(); + topic.subscribe('basemaps/updateBasemap', lang.hitch(this, 'updateBasemap')); + }, + + initializeBasemaps: function () { + if (this.galleryOptions.basemaps) { + // if the basemaps to show is not explicitly set, get them from the gallery's basemap array + this.basemapsToShow = this.basemapsToShow || array.map(this.galleryOptions.basemaps, function (basemap) { + return basemap.id; }); - // if (this.map.getBasemap() !== this.mapStartBasemap) { //based off the title of custom basemaps in viewer.js config - // this.gallery.select(this.mapStartBasemap); - // } - this.gallery.startup(); + } else { + // no basemaps? use the Esri basemaps + if (!this.basemaps || Object.keys(this.basemaps).length < 1) { + this.basemaps = lang.clone(esriBasemaps); + this.galleryOptions.showArcGISBasemaps = false; + } + + // if the basemaps to show is not explicitly set, get them from the basemap object + this.basemapsToShow = this.basemapsToShow || Object.keys(this.basemaps); + + var basemaps = []; + array.forEach(this.basemapsToShow, lang.hitch(this, function (key) { + var map = this.basemaps[key]; + // determine if it is a custom basemap or an esri basemap + if (map.basemap && map.basemap.declaredClass === 'esri.dijit.Basemap') { + var basemap = map.basemap; + basemap.title = map.title || basemap.title; + basemap.id = key; + basemaps.push(basemap); + } else { + if (!esriBasemaps[key]) { + map.basemap.title = map.title || map.basemap.title; + esriBasemaps[key] = map.basemap; + } + map.title = map.title || esriBasemaps[key].title; + this.galleryOptions.showArcGISBasemaps = false; + } + })); + this.galleryOptions.basemaps = basemaps; + } + + // if the starting basemap is not explicitly set, get it from the map + this.mapStartBasemap = this.mapStartBasemap || this.map.getBasemap(); + + // check to make sure the starting basemap is found in the basemaps object + if (array.indexOf(this.basemapsToShow, this.mapStartBasemap) < 0) { + this.mapStartBasemap = this.basemapsToShow[0]; } + }, + + createBasemapGallery: function () { + var opts = lang.mixin({ + map: this.map + }, this.galleryOptions); + this.gallery = new BasemapGallery(opts); + this.gallery.startup(); + if (this.galleryOptions.showArcGISBasemaps) { + this.gallery.on('load', lang.hitch(this, 'buildMenu')); + } else { + this.buildMenu(); + } + }, + buildMenu: function () { this.menu = new DropDownMenu({ - style: 'display: none;' //, - //baseClass: this.menuClass + style: 'display: none;' }); - array.forEach(this.basemapsToShow, function (basemap) { if (this.basemaps.hasOwnProperty(basemap)) { var menuItem = new MenuItem({ id: basemap, label: this.basemaps[basemap].title, - iconClass: (basemap == this.mapStartBasemap) ? 'selectedIcon' : 'emptyIcon', - onClick: lang.hitch(this, function () { - if (basemap !== this.currentBasemap) { - this.currentBasemap = basemap; - if (this.mode === 'custom') { - this.gallery.select(basemap); - } else { - this.map.setBasemap(basemap); - } - var ch = this.menu.getChildren(); - array.forEach(ch, function (c) { - if (c.id == basemap) { - c.set('iconClass', 'selectedIcon'); - } else { - c.set('iconClass', 'emptyIcon'); - } - }); - } - }) + iconClass: (basemap === this.mapStartBasemap) ? 'selectedIcon' : 'emptyIcon', + onClick: lang.hitch(this, 'updateBasemap', basemap) }); this.menu.addChild(menuItem); } }, this); - this.dropDownButton.set('dropDown', this.menu); + this.setStartingBasemap(); }, - startup: function () { - this.inherited(arguments); - if (this.mode === 'custom') { - if (this.map.getBasemap() !== this.mapStartBasemap) { //based off the title of custom basemaps in viewer.js config - this.gallery.select(this.mapStartBasemap); + + setStartingBasemap: function () { + if (this.mapStartBasemap && (this.gallery.get(this.mapStartBasemap) || esriBasemaps[this.mapStartBasemap])) { + this.updateBasemap(this.mapStartBasemap); + } + }, + + updateBasemap: function (basemap) { + if (basemap !== this.currentBasemap && (array.indexOf(this.basemapsToShow, basemap) !== -1)) { + if (this.gallery.get(basemap)) { + this.gallery.select(basemap); + } else if (esriBasemaps[basemap]) { + this.gallery._removeBasemapLayers(); + this.gallery._removeReferenceLayer(); + this.map.setBasemap(basemap); + } else { + topic.publish('viewer/error', 'Invalid basemap selected.'); + return; } - } else { - if (this.mapStartBasemap) { - if (this.map.getBasemap() !== this.mapStartBasemap) { //based off the agol basemap name - this.map.setBasemap(this.mapStartBasemap); + this.currentBasemap = basemap; + var ch = this.menu.getChildren(); + array.forEach(ch, function (c) { + if (c.id === basemap) { + c.set('iconClass', 'selectedIcon'); + } else { + c.set('iconClass', 'emptyIcon'); } - } + }); } } }); diff --git a/viewer/js/gis/dijit/Basemaps/nls/es/resource.js b/viewer/js/gis/dijit/Basemaps/nls/es/resource.js new file mode 100644 index 000000000..48f8546d9 --- /dev/null +++ b/viewer/js/gis/dijit/Basemaps/nls/es/resource.js @@ -0,0 +1,3 @@ +define ({ + title: 'Mapas base' +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Basemaps/nls/fr/resource.js b/viewer/js/gis/dijit/Basemaps/nls/fr/resource.js new file mode 100644 index 000000000..1717b565f --- /dev/null +++ b/viewer/js/gis/dijit/Basemaps/nls/fr/resource.js @@ -0,0 +1,3 @@ +define ({ + title: 'Fond de carte' +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Basemaps/nls/pt-br/resource.js b/viewer/js/gis/dijit/Basemaps/nls/pt-br/resource.js new file mode 100644 index 000000000..48f8546d9 --- /dev/null +++ b/viewer/js/gis/dijit/Basemaps/nls/pt-br/resource.js @@ -0,0 +1,3 @@ +define ({ + title: 'Mapas base' +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Basemaps/nls/pt-pt/resource.js b/viewer/js/gis/dijit/Basemaps/nls/pt-pt/resource.js new file mode 100644 index 000000000..d67f99c97 --- /dev/null +++ b/viewer/js/gis/dijit/Basemaps/nls/pt-pt/resource.js @@ -0,0 +1,3 @@ +define({ + title: 'Mapas base' +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Basemaps/nls/resource.js b/viewer/js/gis/dijit/Basemaps/nls/resource.js index b7dace410..99c7c0fae 100644 --- a/viewer/js/gis/dijit/Basemaps/nls/resource.js +++ b/viewer/js/gis/dijit/Basemaps/nls/resource.js @@ -1,5 +1,9 @@ define ({ root: { title: 'Basemaps' - } + }, + 'es': true, + 'fr': true, + 'pt-br': true, + 'pt-pt': true }); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Bookmarks.js b/viewer/js/gis/dijit/Bookmarks.js index 194c66972..0082d887f 100644 --- a/viewer/js/gis/dijit/Bookmarks.js +++ b/viewer/js/gis/dijit/Bookmarks.js @@ -1,41 +1,42 @@ define([ - 'dojo/_base/declare', - 'dijit/_WidgetBase', - 'esri/dijit/Bookmarks', - 'dojo/json', - 'dojo/cookie', - 'dojo/_base/lang', - 'xstyle/css!./Bookmarks/css/Bookmarks.css' + 'dojo/_base/declare', + 'dijit/_WidgetBase', + 'esri/dijit/Bookmarks', + 'dojo/json', + 'dojo/cookie', + 'dojo/_base/lang', + 'xstyle/css!./Bookmarks/css/Bookmarks.css' ], function (declare, _WidgetBase, Bookmarks, json, cookie, lang) { - return declare([_WidgetBase], { - declaredClass: 'gis.digit.Bookmarks', - postCreate: function () { - this.inherited(arguments); - var bookmarks = this.bookmarks; // from the options passed in - this.bookmarkItems = cookie('bookmarkItems'); - if (this.bookmarkItems === undefined) { - this.bookmarkItems = []; - } else { - this.bookmarkItems = json.parse(this.bookmarkItems); - } + return declare([_WidgetBase], { + declaredClass: 'gis.digit.Bookmarks', + postCreate: function () { + this.inherited(arguments); + var bookmarks = this.bookmarks; // from the options passed in + this.bookmarkItems = cookie('bookmarkItems'); + if (this.bookmarkItems === undefined) { + this.bookmarkItems = []; + } else { + this.bookmarkItems = json.parse(this.bookmarkItems); + } - this.bookmarks = new Bookmarks({ - map: this.map, - editable: this.editable, - bookmarks: lang.mixin(this.bookmarkItems, bookmarks) - }, this.domNode); + this.bookmarks = new Bookmarks({ + map: this.map, + id: this.id + '_esri', + editable: this.editable, + bookmarks: lang.mixin(this.bookmarkItems, bookmarks) + }, this.domNode); - this.connect(this.bookmarks, 'onEdit', 'setBookmarks'); - this.connect(this.bookmarks, 'onRemove', 'setBookmarks'); - }, - setBookmarks: function () { - cookie('bookmarkItems', json.stringify(this.bookmarks.toJson()), { - expires: 365 - }); - }, - _export: function () { - return json.stringify(this.bookmarks.toJson()); - } - }); + this.connect(this.bookmarks, 'onEdit', 'setBookmarks'); + this.connect(this.bookmarks, 'onRemove', 'setBookmarks'); + }, + setBookmarks: function () { + cookie('bookmarkItems', json.stringify(this.bookmarks.toJson()), { + expires: 365 + }); + }, + _export: function () { + return json.stringify(this.bookmarks.toJson()); + } + }); }); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Directions.js b/viewer/js/gis/dijit/Directions.js index 7c61df263..88fcbac5d 100644 --- a/viewer/js/gis/dijit/Directions.js +++ b/viewer/js/gis/dijit/Directions.js @@ -1,19 +1,20 @@ define([ - 'dojo/_base/declare', - 'dijit/_WidgetBase', - 'dijit/_TemplatedMixin', - 'esri/dijit/Directions', - 'dojo/text!./Directions/templates/Directions.html', - 'dojo/_base/lang', - 'dijit/Menu', - 'dijit/MenuItem', - 'dijit/PopupMenuItem', - 'dijit/MenuSeparator', - 'esri/geometry/Point', - 'esri/SpatialReference', - 'dojo/topic', - 'dojo/i18n!./Directions/nls/resource' -], function (declare, _WidgetBase, _TemplatedMixin, Directions, template, lang, Menu, MenuItem, PopupMenuItem, MenuSeparator, Point, SpatialReference, topic, i18n) { + 'dojo/_base/declare', + 'dijit/_WidgetBase', + 'dijit/_TemplatedMixin', + 'esri/dijit/Directions', + 'dojo/text!./Directions/templates/Directions.html', + 'dojo/_base/lang', + 'dijit/Menu', + 'dijit/MenuItem', + 'dijit/PopupMenuItem', + 'dijit/MenuSeparator', + 'esri/geometry/Point', + 'esri/SpatialReference', + 'dojo/topic', + 'dojo/i18n!./Directions/nls/resource', + 'dojo/dom-style' +], function (declare, _WidgetBase, _TemplatedMixin, Directions, template, lang, Menu, MenuItem, PopupMenuItem, MenuSeparator, Point, SpatialReference, topic, i18n, domStyle) { return declare([_WidgetBase, _TemplatedMixin], { templateString: template, @@ -25,14 +26,16 @@ define([ }, this.options), this.directionsNode); this.directions.startup(); - //temp fix for 3.12 and 3.13 map click button. + //temp fix for 3.12 and 3.13 map click button. if (this.directions._activateButton) { - this.directions._activateButton.style.display = 'none'; + domStyle.set(this.directions._activateButton, 'display', 'none'); } else if (this.directions._activateButtonNode) { - this.directions._activateButtonNode.style.display = 'none'; - this.directions._addDestinationNode.style['float'] = 'inherit'; - this.directions._optionsButtonNode.style['float'] = 'inherit'; - this.directions._optionsButtonNode.style.marginRight = '5px'; + domStyle.set(this.directions._activateButtonNode, 'display', 'none'); + domStyle.set(this.directions._addDestinationNode, 'float', 'inherit'); + domStyle.set(this.directions._optionsButtonNode, { + 'float': 'inherit', + marginRight: '5px' + }); } if (this.mapRightClickMenu) { @@ -130,4 +133,4 @@ define([ }); } }); -}); \ No newline at end of file +}); diff --git a/viewer/js/gis/dijit/Directions/nls/es/resource.js b/viewer/js/gis/dijit/Directions/nls/es/resource.js new file mode 100644 index 000000000..0f1f0d9e0 --- /dev/null +++ b/viewer/js/gis/dijit/Directions/nls/es/resource.js @@ -0,0 +1,23 @@ +define ({ + labels: { + startAtMyLocation: 'comenzará a mi ubicación', + endAtMyLocation: 'terminar en mi ubicación', + clearStops: 'paradas claras', + addStop: 'Añadir parada', + directionsToHere: 'Direcciones a aquí', + directionsFromHere: 'Direcciones de aquí', + useMyLocationAsStart: 'Usar mi ubicación como punto de inicio', + useMyLocationAsEnd: 'Usar mi ubicación como punto final', + directions: 'Direcciones' + }, + errors: { + geoLocation: { + title: 'Error', + message: 'No geolocalización apoyado por su hojeanr.' + }, + location: { + title: 'Error', + message: 'Hubo un problema con su ubicación: ' + } + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Directions/nls/fr/resource.js b/viewer/js/gis/dijit/Directions/nls/fr/resource.js new file mode 100644 index 000000000..2cc3dd12c --- /dev/null +++ b/viewer/js/gis/dijit/Directions/nls/fr/resource.js @@ -0,0 +1,23 @@ +define ({ + labels: { + startAtMyLocation: 'Commencer à mon endroit', + endAtMyLocation: 'Terminer à mon endroit', + clearStops: 'Supprimer les arrêts', + addStop: 'Ajouter un arrêt', + directionsToHere: 'Directions vers ici', + directionsFromHere: 'Directions à partir d\'ici', + useMyLocationAsStart: 'Utiliser ma position comme point de départ', + useMyLocationAsEnd: 'Utiliser ma position comme point final', + directions: 'Directions' + }, + errors: { + geoLocation: { + title: 'Erreur', + message: 'Géolocalisation non supporté par votre navigateur.' + }, + location: { + title: 'Erreur', + message: 'Il y a un problème pour obtenir votre position: ' + } + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Directions/nls/pt-br/resource.js b/viewer/js/gis/dijit/Directions/nls/pt-br/resource.js new file mode 100644 index 000000000..51bf9d23f --- /dev/null +++ b/viewer/js/gis/dijit/Directions/nls/pt-br/resource.js @@ -0,0 +1,23 @@ +define({ + labels: { + startAtMyLocation: 'Inicie na minha Localização', + endAtMyLocation: 'Termine na minha Localização', + clearStops: 'Limpar paradas', + addStop: 'Adicionar parada', + directionsToHere: 'Direções para aqui', + directionsFromHere: 'Direções daqui', + useMyLocationAsStart: 'Use minha Localização como ponto de início', + useMyLocationAsEnd: 'Use minha Localização como ponto final', + directions: 'Direções' + }, + errors: { + geoLocation: { + title: 'Erro', + message: 'GeoLocalização não suportada no seu navegador.' + }, + location: { + title: 'Erro', + message: 'Houve um problema ao buscar sua Localização: ' + } + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Directions/nls/pt-pt/resource.js b/viewer/js/gis/dijit/Directions/nls/pt-pt/resource.js new file mode 100644 index 000000000..e1ccff40e --- /dev/null +++ b/viewer/js/gis/dijit/Directions/nls/pt-pt/resource.js @@ -0,0 +1,23 @@ +define({ + labels: { + startAtMyLocation: 'iniciar na minha localização', + endAtMyLocation: 'terminar na minha localização', + clearStops: 'limpar paragens', + addStop: 'Adicionar paragem', + directionsToHere: 'Direcções para aqui', + directionsFromHere: 'Direcções a partir daqui', + useMyLocationAsStart: 'Usar a minha localização como ponto inicial', + useMyLocationAsEnd: 'Usar a minha localização como ponto final', + directions: 'Direcções' + }, + errors: { + geoLocation: { + title: 'Erro', + message: 'GeoLocalização não suportada no seu navegador.' + }, + location: { + title: 'Erro', + message: 'Ocorreu um problema ao obter a sua localização: ' + } + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Directions/nls/resource.js b/viewer/js/gis/dijit/Directions/nls/resource.js index 125b2e678..b1db86f01 100644 --- a/viewer/js/gis/dijit/Directions/nls/resource.js +++ b/viewer/js/gis/dijit/Directions/nls/resource.js @@ -21,5 +21,9 @@ define ({ message: 'There was a problem getting your location: ' } } - } + }, + 'es': true, + 'fr': true, + 'pt-br': true, + 'pt-pt': true }); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Draw.js b/viewer/js/gis/dijit/Draw.js index 7a04c7cb8..c7934f1b3 100644 --- a/viewer/js/gis/dijit/Draw.js +++ b/viewer/js/gis/dijit/Draw.js @@ -1,27 +1,27 @@ define([ - 'dojo/_base/declare', - 'dijit/_WidgetBase', - 'dijit/_TemplatedMixin', - 'dijit/_WidgetsInTemplateMixin', - 'dojo/_base/lang', - 'dojo/_base/Color', - 'esri/toolbars/draw', - 'esri/layers/GraphicsLayer', - 'esri/graphic', - 'esri/renderers/SimpleRenderer', - 'dojo/text!./Draw/templates/Draw.html', - 'esri/renderers/UniqueValueRenderer', - 'esri/symbols/SimpleMarkerSymbol', - 'esri/symbols/SimpleLineSymbol', - 'esri/symbols/SimpleFillSymbol', - 'esri/layers/FeatureLayer', - 'dojo/topic', - 'dojo/aspect', - 'dojo/i18n!./Draw/nls/resource', + 'dojo/_base/declare', + 'dijit/_WidgetBase', + 'dijit/_TemplatedMixin', + 'dijit/_WidgetsInTemplateMixin', + 'dojo/_base/lang', + 'dojo/_base/Color', + 'esri/toolbars/draw', + 'esri/layers/GraphicsLayer', + 'esri/graphic', + 'esri/renderers/SimpleRenderer', + 'dojo/text!./Draw/templates/Draw.html', + 'esri/renderers/UniqueValueRenderer', + 'esri/symbols/SimpleMarkerSymbol', + 'esri/symbols/SimpleLineSymbol', + 'esri/symbols/SimpleFillSymbol', + 'esri/layers/FeatureLayer', + 'dojo/topic', + 'dojo/aspect', + 'dojo/i18n!./Draw/nls/resource', - 'dijit/form/Button', - 'xstyle/css!./Draw/css/Draw.css', - 'xstyle/css!./Draw/css/adw-icons.css' + 'dijit/form/Button', + 'xstyle/css!./Draw/css/Draw.css', + 'xstyle/css!./Draw/css/adw-icons.css' ], function (declare, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, lang, Color, Draw, GraphicsLayer, Graphic, SimpleRenderer, drawTemplate, UniqueValueRenderer, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, FeatureLayer, topic, aspect, i18n) { // main draw dijit @@ -94,12 +94,12 @@ define([ mode: FeatureLayer.MODE_SNAPSHOT }); this.polygonRenderer = new UniqueValueRenderer(new SimpleFillSymbol(), 'ren', null, null, ', '); - this.polygonRenderer.addValue({ - value: 1, - symbol: new SimpleFillSymbol({ - color: [255,170,0,255], + this.polygonRenderer.addValue({ + value: 1, + symbol: new SimpleFillSymbol({ + color: [255, 170, 0, 255], outline: { - color: [255,170,0,255], + color: [255, 170, 0, 255], width: 1, type: 'esriSLS', style: 'esriSLSSolid' @@ -146,36 +146,36 @@ define([ disconnectMapClick: function () { topic.publish('mapClickMode/setCurrent', 'draw'); this.enableStopButtons(); - // dojo.disconnect(this.mapClickEventHandle); - // this.mapClickEventHandle = null; + // dojo.disconnect(this.mapClickEventHandle); + // this.mapClickEventHandle = null; }, connectMapClick: function () { topic.publish('mapClickMode/setDefault'); this.disableStopButtons(); - // if (this.mapClickEventHandle === null) { - // this.mapClickEventHandle = dojo.connect(this.map, 'onClick', this.mapClickEventListener); - // } + // if (this.mapClickEventHandle === null) { + // this.mapClickEventHandle = dojo.connect(this.map, 'onClick', this.mapClickEventListener); + // } }, onDrawToolbarDrawEnd: function (evt) { this.drawToolbar.deactivate(); this.drawModeTextNode.innerText = this.i18n.labels.currentDrawModeNone; var graphic; switch (evt.geometry.type) { - case 'point': - graphic = new Graphic(evt.geometry); - this.pointGraphics.add(graphic); - break; - case 'polyline': - graphic = new Graphic(evt.geometry); - this.polylineGraphics.add(graphic); - break; - case 'polygon': - graphic = new Graphic(evt.geometry, null, { - ren: 1 - }); - this.polygonGraphics.add(graphic); - break; - default: + case 'point': + graphic = new Graphic(evt.geometry); + this.pointGraphics.add(graphic); + break; + case 'polyline': + graphic = new Graphic(evt.geometry); + this.polylineGraphics.add(graphic); + break; + case 'polygon': + graphic = new Graphic(evt.geometry, null, { + ren: 1 + }); + this.polygonGraphics.add(graphic); + break; + default: } this.connectMapClick(); }, @@ -197,25 +197,24 @@ define([ this.disableStopButtons(); }, disableStopButtons: function () { - this.stopDrawingButton.set( 'disabled', true ); - this.eraseDrawingButton.set( 'disabled', !this.noGraphics() ); + this.stopDrawingButton.set('disabled', true); + this.eraseDrawingButton.set('disabled', !this.noGraphics()); }, enableStopButtons: function () { - this.stopDrawingButton.set( 'disabled', false ); - this.eraseDrawingButton.set( 'disabled', !this.noGraphics() ); + this.stopDrawingButton.set('disabled', false); + this.eraseDrawingButton.set('disabled', !this.noGraphics()); }, noGraphics: function () { - if ( this.pointGraphics.graphics.length > 0 ) { + if (this.pointGraphics.graphics.length > 0) { return true; - } else if ( this.polylineGraphics.graphics.length > 0 ) { + } else if (this.polylineGraphics.graphics.length > 0) { return true; - } else if ( this.polygonGraphics.graphics.length > 0 ) { + } else if (this.polygonGraphics.graphics.length > 0) { return true; } else { return false; } - return false; }, onLayoutChange: function (open) { diff --git a/viewer/js/gis/dijit/Draw/css/Draw.css b/viewer/js/gis/dijit/Draw/css/Draw.css index d1943125f..cd2618c97 100644 --- a/viewer/js/gis/dijit/Draw/css/Draw.css +++ b/viewer/js/gis/dijit/Draw/css/Draw.css @@ -1,18 +1,15 @@ -.gis_DrawDijit { -} - .gis_DrawDijit .outerList>li { margin-bottom: 1em; } .gis_DrawDijit .list-unstyled { - padding-left: 0px; + padding-left: 0; list-style-type: none; list-style-position: outside; list-style-image: none; } .gis_DrawDijit .list-inline { - padding-left: 0px; + padding-left: 0; margin-left: -5px; list-style-type: none; list-style-position: outside; @@ -23,75 +20,10 @@ display: inline-block; } -.gis_DrawDijit .drawButton { - width: 50px; -} - -.gis_DrawDijit .stopIcon { - color: red; -} - -.gis_DrawDijit .drawButton .dijitButtonText { - /*display: none;*/ -} -.gis_DrawDijit .polyIcon { - background-image: url(../images/toolbar_icons.png); - background-position: -68px 0; - width: 16px; - height: 16px; -} - -.gis_DrawDijit .pointIcon { - background-image: url(../images/toolbar_icons.png); - background-position: 0px 0; - width: 16px; - height: 16px; -} - -.gis_DrawDijit .circleDrawIcon { - background-image: url(../images/toolbar_icons.png); - background-position: -390px 0; - width: 16px; - height: 16px; -} - -.gis_DrawDijit .lineIcon { - background-image: url(../images/toolbar_icons.png); - background-position: -34px 0; - width: 16px; - height: 16px; -} - -.gis_DrawDijit .freehandDrawIcon { - background-image: url(../images/toolbar_icons.png); - background-position: -102px 0; - width: 16px; - height: 16px; -} - -.gis_DrawDijit .freehandPolygonDrawIcon { - background-image: url(../images/toolbar_icons_2.png); - background-position: -473px 0; - width: 16px; - height: 16px; -} - -.gis_DrawDijit .clearIcon { - background-image: url(../images/clear.png); - width: 16px; - height: 16px; -} - .gis_DrawDijit .formContainer { - /*border: 1px solid #bbb;*/ - margin-bottom: -1px; width: 100%; } -.gis_DrawDijit .buttonActionBar { - /*background-color: #F2F2F2; - border: 1px solid #CDCDCD;*/ - padding: 3px 0px 2px 0px; - text-align: right; - width: 100%; +.gis_DrawDijit .dijitButtonNode .dijitIcon { + margin-right: 0; } \ No newline at end of file diff --git a/viewer/js/gis/dijit/Draw/images/clear.png b/viewer/js/gis/dijit/Draw/images/clear.png deleted file mode 100644 index 0b82e3f88..000000000 Binary files a/viewer/js/gis/dijit/Draw/images/clear.png and /dev/null differ diff --git a/viewer/js/gis/dijit/Draw/images/toolbar_icons.png b/viewer/js/gis/dijit/Draw/images/toolbar_icons.png deleted file mode 100644 index 02fcda387..000000000 Binary files a/viewer/js/gis/dijit/Draw/images/toolbar_icons.png and /dev/null differ diff --git a/viewer/js/gis/dijit/Draw/nls/es/resource.js b/viewer/js/gis/dijit/Draw/nls/es/resource.js new file mode 100644 index 000000000..32e5d4098 --- /dev/null +++ b/viewer/js/gis/dijit/Draw/nls/es/resource.js @@ -0,0 +1,14 @@ +define ({ + labels: { + point: 'Punto', + circle: 'Circulo', + polyline: 'Polilínea', + freehandPolyline: 'Polilínea a mano alzada', + polygon: 'Polígono', + freehandPolygon: 'Polígono a mano alzada', + stopDrawing: 'Comienzo dibujo', + clearDrawing: 'Despejar dibujo', + currentDrawMode: 'El modo de dibujo:', + currentDrawModeNone: 'Nada' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Draw/nls/fr/resource.js b/viewer/js/gis/dijit/Draw/nls/fr/resource.js new file mode 100644 index 000000000..93c4c0146 --- /dev/null +++ b/viewer/js/gis/dijit/Draw/nls/fr/resource.js @@ -0,0 +1,14 @@ +define ({ + labels: { + point: 'Point', + circle: 'Cercle', + polyline: 'Polyline', + freehandPolyline: 'Polyligne à main levée', + polygon: 'Polygone', + freehandPolygon: 'Polygone à main levée', + stopDrawing: 'Terminer le dessin', + clearDrawing: 'Effacer le dessin', + currentDrawMode: 'Mode de dessin:', + currentDrawModeNone: 'Aucun' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Draw/nls/pt-br/resource.js b/viewer/js/gis/dijit/Draw/nls/pt-br/resource.js new file mode 100644 index 000000000..4192728c6 --- /dev/null +++ b/viewer/js/gis/dijit/Draw/nls/pt-br/resource.js @@ -0,0 +1,14 @@ +define({ + labels: { + point: 'Ponto', + circle: 'Círculo', + polyline: 'Polilinha', + freehandPolyline: 'Polilinha a Mão Livre', + polygon: 'Polígono', + freehandPolygon: 'Polígono a Mão Livre', + stopDrawing: 'Parar de Desenhar', + clearDrawing: 'Limpar Desenhos', + currentDrawMode: 'Modo de desenho atual:', + currentDrawModeNone: 'Nenhum' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Draw/nls/pt-pt/resource.js b/viewer/js/gis/dijit/Draw/nls/pt-pt/resource.js new file mode 100644 index 000000000..9dc6144bb --- /dev/null +++ b/viewer/js/gis/dijit/Draw/nls/pt-pt/resource.js @@ -0,0 +1,14 @@ +define({ + labels: { + point: 'Ponto', + circle: 'Círculo', + polyline: 'Polilinha', + freehandPolyline: 'Polilinha à mão livre', + polygon: 'Polígono', + freehandPolygon: 'Polígono à mão livre', + stopDrawing: 'Parar de desenhar', + clearDrawing: 'Limpar desenhos', + currentDrawMode: 'Modo de desenho actual:', + currentDrawModeNone: 'Nenhum' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Draw/nls/resource.js b/viewer/js/gis/dijit/Draw/nls/resource.js index 29c6ab534..b55a4fd3c 100644 --- a/viewer/js/gis/dijit/Draw/nls/resource.js +++ b/viewer/js/gis/dijit/Draw/nls/resource.js @@ -12,5 +12,9 @@ define ({ currentDrawMode: 'Current draw mode:', currentDrawModeNone: 'None' } - } + }, + 'es': true, + 'fr': true, + 'pt-br': true, + 'pt-pt': true }); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Draw/templates/Draw.html b/viewer/js/gis/dijit/Draw/templates/Draw.html index 2fe283f7a..eabb9e1c0 100644 --- a/viewer/js/gis/dijit/Draw/templates/Draw.html +++ b/viewer/js/gis/dijit/Draw/templates/Draw.html @@ -1,100 +1,85 @@
-
-
    +
      +
    • +
        +
      • + +
      • +
      • + +
      • +
      • + +
      • +
      • + +
      • +
      • + +
      • +
      • + +
      • +
      • + +
      • +
      • + +
      • +
      +
    • +
    • +
      + ${i18n.labels.currentDrawMode} + ${i18n.labels.currentDrawModeNone} +
      +
    • -
    • -
        - -
      • - -
      • - -
      • - -
      • - -
      • - -
      • - -
      • - -
      • - -
      • - -
      • - -
      • - -
      • - -
      • - -
      • - -
      • - -
      • - -
      -
    • - -
    • -
      - ${i18n.labels.currentDrawMode} - ${i18n.labels.currentDrawModeNone} -
      -
    • - -
    - -
+
-
diff --git a/viewer/js/gis/dijit/Editor/nls/es/resource.js b/viewer/js/gis/dijit/Editor/nls/es/resource.js new file mode 100644 index 000000000..445721fa7 --- /dev/null +++ b/viewer/js/gis/dijit/Editor/nls/es/resource.js @@ -0,0 +1,6 @@ +define ({ + labels: { + startEditing: 'Comenzar a editar', + stopEditing: 'Detener la edición' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Editor/nls/fr/resource.js b/viewer/js/gis/dijit/Editor/nls/fr/resource.js new file mode 100644 index 000000000..237f02020 --- /dev/null +++ b/viewer/js/gis/dijit/Editor/nls/fr/resource.js @@ -0,0 +1,6 @@ +define ({ + labels: { + startEditing: 'Commencez à éditer', + stopEditing: 'Arrêter l\'édition' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Editor/nls/pt-br/resource.js b/viewer/js/gis/dijit/Editor/nls/pt-br/resource.js new file mode 100644 index 000000000..79974dfec --- /dev/null +++ b/viewer/js/gis/dijit/Editor/nls/pt-br/resource.js @@ -0,0 +1,6 @@ +define({ + labels: { + startEditing: 'Iniciar Edição', + stopEditing: 'Parar Edição' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Editor/nls/pt-pt/resource.js b/viewer/js/gis/dijit/Editor/nls/pt-pt/resource.js new file mode 100644 index 000000000..5c499062e --- /dev/null +++ b/viewer/js/gis/dijit/Editor/nls/pt-pt/resource.js @@ -0,0 +1,6 @@ +define({ + labels: { + startEditing: 'Iniciar edição', + stopEditing: 'Parar edição' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Editor/nls/resource.js b/viewer/js/gis/dijit/Editor/nls/resource.js index e24f161fb..5320f6518 100644 --- a/viewer/js/gis/dijit/Editor/nls/resource.js +++ b/viewer/js/gis/dijit/Editor/nls/resource.js @@ -4,5 +4,9 @@ define ({ startEditing: 'Start editing', stopEditing: 'Stop editing' } - } + }, + 'es': true, + 'fr': true, + 'pt-br': true, + 'pt-pt': true }); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Find.js b/viewer/js/gis/dijit/Find.js index b39eb675e..e8bea99f7 100644 --- a/viewer/js/gis/dijit/Find.js +++ b/viewer/js/gis/dijit/Find.js @@ -1,596 +1,598 @@ -define( - [ - 'dojo/_base/declare', - 'dijit/_WidgetBase', - 'dijit/_TemplatedMixin', - 'dijit/_WidgetsInTemplateMixin', - 'dojo/dom-construct', - 'dojo/_base/lang', - 'dojo/_base/array', - 'dojo/on', - 'dojo/keys', - 'dojo/dom-style', - 'dojo/store/Memory', - 'dgrid/OnDemandGrid', - 'dgrid/Selection', - 'dgrid/Keyboard', - 'dgrid/extensions/ColumnResizer', - 'esri/layers/GraphicsLayer', - 'esri/symbols/jsonUtils', - 'esri/graphicsUtils', - 'esri/tasks/FindTask', - 'esri/tasks/FindParameters', - 'esri/geometry/Extent', - 'dojo/text!./Find/templates/Find.html', - 'dojo/i18n!./Find/nls/resource', +define([ + 'dojo/_base/declare', + 'dijit/_WidgetBase', + 'dijit/_TemplatedMixin', + 'dijit/_WidgetsInTemplateMixin', + 'dojo/dom-construct', + 'dojo/_base/lang', + 'dojo/_base/array', + 'dojo/on', + 'dojo/keys', + 'dojo/dom-style', + 'dojo/store/Memory', + 'dgrid/OnDemandGrid', + 'dgrid/Selection', + 'dgrid/Keyboard', + 'dgrid/extensions/ColumnResizer', + 'esri/layers/GraphicsLayer', + 'esri/symbols/jsonUtils', + 'esri/graphicsUtils', + 'esri/tasks/FindTask', + 'esri/tasks/FindParameters', + 'esri/geometry/Extent', + 'dojo/text!./Find/templates/Find.html', + 'dojo/i18n!./Find/nls/resource', - 'dijit/form/Form', - 'dijit/form/DropDownButton', - 'dijit/TooltipDialog', - 'dijit/form/FilteringSelect', - 'dijit/form/ValidationTextBox', - 'dijit/form/CheckBox', - 'xstyle/css!./Find/css/Find.css' - ], function ( - declare, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, domConstruct, lang, array, on, keys, domStyle, Memory, - OnDemandGrid, Selection, Keyboard, ColumnResizer, GraphicsLayer, symbolUtils, graphicsUtils, FindTask, FindParameters, Extent, - FindTemplate, i18n - ) { - return declare( - [_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], { - widgetsInTemplate: true, - templateString: FindTemplate, - baseClass: 'gis_AdvancedFindDijit', - i18n: i18n, - spatialReference: null, - showOptionsButton: false, - zoomOptions: { - select: true, - deselect: false + 'dijit/form/Form', + 'dijit/form/DropDownButton', + 'dijit/TooltipDialog', + 'dijit/form/FilteringSelect', + 'dijit/form/ValidationTextBox', + 'dijit/form/CheckBox', + 'dijit/form/Button', + 'xstyle/css!./Find/css/Find.css' +], function ( + declare, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, domConstruct, lang, array, on, keys, domStyle, Memory, + OnDemandGrid, Selection, Keyboard, ColumnResizer, GraphicsLayer, symbolUtils, graphicsUtils, FindTask, FindParameters, Extent, + FindTemplate, i18n +) { + + return declare( + [_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], { + widgetsInTemplate: true, + templateString: FindTemplate, + baseClass: 'gis_AdvancedFindDijit', + i18n: i18n, + spatialReference: null, + showOptionsButton: false, + zoomOptions: { + select: true, + deselect: false + }, + defaultResultsSymbols: { + point: { + type: 'esriSMS', + style: 'esriSMSCircle', + size: 25, + color: [0, 255, 255, 32], + angle: 0, + xoffset: 0, + yoffset: 0, + outline: { + type: 'esriSLS', + style: 'esriSLSSolid', + color: [0, 255, 255, 255], + width: 2 + } }, - defaultResultsSymbols: { - point: { - type: 'esriSMS', - style: 'esriSMSCircle', - size: 25, - color: [0, 255, 255, 32], - angle: 0, - xoffset: 0, - yoffset: 0, - outline: { - type: 'esriSLS', - style: 'esriSLSSolid', - color: [0, 255, 255, 255], - width: 2 - } - }, - polyline: { + polyline: { + type: 'esriSLS', + style: 'esriSLSSolid', + color: [0, 255, 255, 255], + width: 3 + }, + polygon: { + type: 'esriSFS', + style: 'esriSFSSolid', + color: [0, 255, 255, 32], + outline: { type: 'esriSLS', style: 'esriSLSSolid', color: [0, 255, 255, 255], width: 3 - }, - polygon: { - type: 'esriSFS', - style: 'esriSFSSolid', - color: [0, 255, 255, 32], - outline: { - type: 'esriSLS', - style: 'esriSLSSolid', - color: [0, 255, 255, 255], - width: 3 - } } - }, - defaultSelectionSymbols: { - point: { - type: 'esriSMS', - style: 'esriSMSCircle', - size: 25, - color: [4, 156, 219, 32], - angle: 0, - xoffset: 0, - yoffset: 0, - outline: { - type: 'esriSLS', - style: 'esriSLSSolid', - color: [4, 156, 219, 255], - width: 2 - } - }, - polyline: { + } + }, + defaultSelectionSymbols: { + point: { + type: 'esriSMS', + style: 'esriSMSCircle', + size: 25, + color: [4, 156, 219, 32], + angle: 0, + xoffset: 0, + yoffset: 0, + outline: { type: 'esriSLS', style: 'esriSLSSolid', color: [4, 156, 219, 255], - width: 3 - }, - polygon: { - type: 'esriSFS', - style: 'esriSFSSolid', - color: [4, 156, 219, 32], - outline: { - type: 'esriSLS', - style: 'esriSLSSolid', - color: [4, 156, 219, 255], - width: 3 - } + width: 2 } }, - postCreate: function () { - this.inherited(arguments); - if (this.showOptionsButton) { - domStyle.set(this.optionsDropDownDijit.domNode, 'display', 'inline-block'); - } - this.initializeGlobalVariables(); - this.addKeyUpHandlerToSearchInput(); - this.initializeQueries(); - this.updateSearchPrompt(); + polyline: { + type: 'esriSLS', + style: 'esriSLSSolid', + color: [4, 156, 219, 255], + width: 3 }, - initializeGlobalVariables: function () { - this.queryIdx = 0; - this.currentQueryEventHandlers = []; - this.gridColumns = null; - if (!this.selectionMode) { - this.selectionMode = 'single'; - } - if (!this.zoomExtentFactor) { - this.zoomExtentFactor = 1.5; - } - if (!this.spatialReference) { - this.spatialReference = this.map.spatialReference.wkid; - } - if (!this.pointExtentSize) { - this.pointExtentSize = this.spatialReference === 4326 ? 0.0001 : 25; + polygon: { + type: 'esriSFS', + style: 'esriSFSSolid', + color: [4, 156, 219, 32], + outline: { + type: 'esriSLS', + style: 'esriSLSSolid', + color: [4, 156, 219, 255], + width: 3 } - }, - addKeyUpHandlerToSearchInput: function () { - this.own( - on( - this.searchTextDijit, 'keyup', lang.hitch( - this, function (evt) { - if (evt.keyCode === keys.ENTER) { - this.search(); - } + } + }, + postCreate: function () { + this.inherited(arguments); + if (this.showOptionsButton) { + domStyle.set(this.optionsDropDownDijit.domNode, 'display', 'inline-block'); + } + this.initializeGlobalVariables(); + this.addKeyUpHandlerToSearchInput(); + this.initializeQueries(); + this.updateSearchPrompt(); + }, + initializeGlobalVariables: function () { + this.queryIdx = 0; + this.currentQueryEventHandlers = []; + this.gridColumns = null; + if (!this.selectionMode) { + this.selectionMode = 'single'; + } + if (!this.zoomExtentFactor) { + this.zoomExtentFactor = 1.5; + } + if (!this.spatialReference) { + this.spatialReference = this.map.spatialReference.wkid; + } + if (!this.pointExtentSize) { + this.pointExtentSize = this.spatialReference === 4326 ? 0.0001 : 25; + } + }, + addKeyUpHandlerToSearchInput: function () { + this.own( + on( + this.searchTextDijit, 'keyup', lang.hitch( + this, function (evt) { + if (evt.keyCode === keys.ENTER) { + this.search(); } - ) + } ) - ); - }, - initializeQueries: function () { - var k = 0, - queryLen = this.queries.length; - for (k = 0; k < queryLen; k++) { - this.queries[k].id = k; - } - this.querySelectDom.style.display = 'none'; - if (queryLen > 1) { - var queryStore = new Memory({ - data: this.queries - }); - this.querySelectDijit.set('store', queryStore); - this.querySelectDijit.set('value', this.queryIdx); - this.querySelectDom.style.display = 'block'; - } - }, - search: function () { - if (this.userInputIsInvalid()) { - this.displayInvalidUserInputMessage(); - return; - } - if (this.queryConfigurationIsInvalid()) { - this.displayInvalidQueryConfigurationMessage(); - return; - } - this.createOrResetResultsGrid(); - this.displayFindMessage(this.i18n.searching); - this.executeFindTask(); - }, - executeFindTask: function () { - var url = this.getQueryInput().query.url; - var findParams = this.getFindParams(); - var findTask = new FindTask(url); - findTask.execute(findParams, lang.hitch(this, this.showResults)); - }, - getQueryInput: function () { - return { - query: this.queries[this.queryIdx] || {}, - searchText: this.searchTextDijit.get('value') - }; - }, - queryConfigurationIsInvalid: function () { - var query = this.getQueryInput().query; - if (!query.url || !query.searchFields || !query.layerIds) { - return true; - } - return false; - }, - userInputIsInvalid: function () { - var userInput = this.getQueryInput().searchText; - if (userInput.length === 0 || this.userInputLessThanMinLength()) { - return true; - } - return false; - }, - userInputLessThanMinLength: function () { - var queryInput = this.getQueryInput(); - if (queryInput.query.minChars && (queryInput.searchText.length < queryInput.query.minChars)) { - return true; - } - return false; - }, - displayInvalidQueryConfigurationMessage: function () { - this.displayFindMessage('There is a problem with the query configuration.'); + ) + ); + }, + initializeQueries: function () { + var k = 0, + queryLen = this.queries.length; + for (k = 0; k < queryLen; k++) { + this.queries[k].id = k; + } + this.querySelectDom.style.display = 'none'; + if (queryLen > 1) { + var queryStore = new Memory({ + data: this.queries + }); + this.querySelectDijit.set('store', queryStore); + this.querySelectDijit.set('value', this.queryIdx); + this.querySelectDom.style.display = 'block'; + } + }, + search: function () { + if (this.userInputIsInvalid()) { + this.displayInvalidUserInputMessage(); return; - }, - displayInvalidUserInputMessage: function () { - var minChars = this.getQueryInput().query.minChars; - this.displayFindMessage('You must enter at least ' + minChars + ' characters.'); + } + if (this.queryConfigurationIsInvalid()) { + this.displayInvalidQueryConfigurationMessage(); return; - }, - displayFindMessage: function (message) { - domConstruct.empty(this.findResultsNode); - this.findResultsNode.innerHTML = message; - this.findResultsNode.style.display = 'block'; - }, - getFindParams: function () { - var queryInput = this.getQueryInput(); - var findParams = new FindParameters(); - findParams.returnGeometry = true; - findParams.layerIds = queryInput.query.layerIds; - findParams.searchFields = queryInput.query.searchFields; - findParams.layerDefinitions = queryInput.query.layerDefs; - findParams.searchText = queryInput.searchText; - findParams.contains = !this.containsSearchText.checked; - findParams.outSpatialReference = { - wkid: this.spatialReference - }; - return findParams; - }, - createOrResetResultsGrid: function () { - if (!this.resultsGrid) { - this.createResultsStore(); - this.createResultsGrid(); - this.attachStandardEventHandlersToResultsGrid(); - } - this.clearResultsGrid(); - this.clearFeatures(); - this.resetResultsGridColumns(); - this.resetResultsGridSort(); - this.resetGridSelectionMode(); - this.attachCustomEventHandlersToResultsGrid(); - }, - createResultsStore: function () { - if (!this.resultsStore) { - this.resultsStore = new Memory({ - idProperty: 'id', - data: [] - }); - } - }, - createResultsGrid: function () { - var Grid = declare([OnDemandGrid, Keyboard, Selection, ColumnResizer]); - this.resultsGrid = new Grid({ - selectionMode: this.selectionMode, - cellNavigation: false, - showHeader: true, - store: this.resultsStore - }, this.findResultsGrid); - this.resultsGrid.startup(); - }, - resetResultsGridColumns: function () { - if (!this.resultsGrid) { - return; - } - var columns = this.queries[this.queryIdx].gridColumns || { - layerName: 'Layer', - foundFieldName: 'Field', - value: 'Result' - }; - if (columns instanceof Array) { - columns = array.filter( - columns, function (column) { - if (typeof column.visible === 'undefined') { - column.visible = true; - } - return column.visible; - } - ); - } - this.resultsGrid.setColumns(columns); - }, - resetResultsGridSort: function () { - if (!this.resultsGrid) { - return; - } - var sort = this.queries[this.queryIdx].sort || [ - { - attribute: 'value', - descending: false - } - ]; - this.resultsGrid.set('sort', sort); - }, - resetGridSelectionMode: function () { - if (!this.resultsGrid) { - return; - } - var selectionMode = this.queries[this.queryIdx].selectionMode || this.selectionMode; - this.resultsGrid.set('selectionMode', selectionMode); - }, - attachStandardEventHandlersToResultsGrid: function () { - if (!this.resultsGrid) { - return; - } - this.own( - this.resultsGrid.on('dgrid-select', lang.hitch(this, 'onResultsGridSelect')) - ); - this.own( - this.resultsGrid.on('dgrid-deselect', lang.hitch(this, 'onResultsGridDeselect')) - ); - this.own( - this.resultsGrid.on('.dgrid-row:dblclick', lang.hitch(this, 'onResultsGridRowClick')) - ); - }, - attachCustomEventHandlersToResultsGrid: function () { - if (!this.resultsGrid) { - return; - } - array.forEach(this.currentQueryEventHandlers, function (handler) { - handler.handle.remove(); - }); - var queryEventHandlers = this.queries[this.queryIdx].customGridEventHandlers || []; - array.forEach(queryEventHandlers, lang.hitch(this, function (handler) { - handler.handle = this.resultsGrid.on(handler.event, lang.hitch(this, handler.handler)); - })); - this.currentQueryEventHandlers = queryEventHandlers; - }, - showResults: function (results) { - var resultText = this.i18n.noResultsLabel; - this.results = results; - if (this.results.length > 0) { - var s = (this.results.length === 1) ? '' : this.i18n.resultsLabel.multipleResultsSuffix; - resultText = this.results.length + ' ' + this.i18n.resultsLabel.labelPrefix + s + ' ' + this.i18n.resultsLabel.labelSuffix; - this.createGraphicsLayerAndSymbols(); - this.parseGridColumnProperties(); - this.addResultsToGraphicsLayer(); - this.zoomToGraphics(this.graphicsLayer.graphics); - this.showResultsGrid(); - } - this.displayFindMessage(resultText); - }, - createGraphicsLayerAndSymbols: function () { - if (!this.graphicsLayer) { - this.graphicsLayer = this.createGraphicsLayer(); - } - if (!this.graphicsSymbols) { - this.graphicsSymbols = this.createGraphicsSymbols(); - } - }, - createGraphicsLayer: function () { - var graphicsLayer = new GraphicsLayer({ - id: this.id + '_findGraphics', - title: 'Find' + } + this.createOrResetResultsGrid(); + this.displayFindMessage(this.i18n.searching); + this.executeFindTask(); + }, + executeFindTask: function () { + var url = this.getQueryInput().query.url; + var findParams = this.getFindParams(); + var findTask = new FindTask(url); + findTask.execute(findParams, lang.hitch(this, this.showResults)); + }, + getQueryInput: function () { + return { + query: this.queries[this.queryIdx] || {}, + searchText: this.searchTextDijit.get('value') + }; + }, + queryConfigurationIsInvalid: function () { + var query = this.getQueryInput().query; + if (!query.url || !query.searchFields || !query.layerIds) { + return true; + } + return false; + }, + userInputIsInvalid: function () { + var userInput = this.getQueryInput().searchText; + if (userInput.length === 0 || this.userInputLessThanMinLength()) { + return true; + } + return false; + }, + userInputLessThanMinLength: function () { + var queryInput = this.getQueryInput(); + if (queryInput.query.minChars && (queryInput.searchText.length < queryInput.query.minChars)) { + return true; + } + return false; + }, + displayInvalidQueryConfigurationMessage: function () { + this.displayFindMessage('There is a problem with the query configuration.'); + return; + }, + displayInvalidUserInputMessage: function () { + var minChars = this.getQueryInput().query.minChars; + this.displayFindMessage('You must enter at least ' + minChars + ' characters.'); + return; + }, + displayFindMessage: function (message) { + domConstruct.empty(this.findResultsNode); + this.findResultsNode.innerHTML = message; + this.findResultsNode.style.display = 'block'; + }, + getFindParams: function () { + var queryInput = this.getQueryInput(); + var findParams = new FindParameters(); + findParams.returnGeometry = true; + findParams.layerIds = queryInput.query.layerIds; + findParams.searchFields = queryInput.query.searchFields; + findParams.layerDefinitions = queryInput.query.layerDefs; + findParams.searchText = queryInput.searchText; + findParams.contains = !this.containsSearchText.checked; + findParams.outSpatialReference = { + wkid: this.spatialReference + }; + return findParams; + }, + createOrResetResultsGrid: function () { + if (!this.resultsGrid) { + this.createResultsStore(); + this.createResultsGrid(); + this.attachStandardEventHandlersToResultsGrid(); + } + this.clearResultsGrid(); + this.clearFeatures(); + this.resetResultsGridColumns(); + this.resetResultsGridSort(); + this.resetGridSelectionMode(); + this.attachCustomEventHandlersToResultsGrid(); + }, + createResultsStore: function () { + if (!this.resultsStore) { + this.resultsStore = new Memory({ + idProperty: 'id', + data: [] }); - graphicsLayer.on('click', lang.hitch(this, 'onGraphicsLayerClick')); - this.map.addLayer(graphicsLayer); - return graphicsLayer; - }, - onGraphicsLayerClick: function (event) { - var zoomOnSelect = this.zoomOptions.select; - this.zoomOptions.select = false; - var row = this.resultsGrid.row(event.graphic.storeid); - this.resultsGrid.select(row); - this.resultsGrid.focus(row.element); - row.element.focus(); - this.zoomOptions.select = zoomOnSelect; - }, - createGraphicsSymbols: function () { - var graphicSymbols = {}, resultSymbolDefinitions, selectionSymbolDefinitions; - resultSymbolDefinitions = lang.mixin(this.defaultResultsSymbols, this.resultsSymbols || {}); - graphicSymbols.resultsSymbols = {}; - graphicSymbols.resultsSymbols.point = symbolUtils.fromJson(resultSymbolDefinitions.point); - graphicSymbols.resultsSymbols.polyline = symbolUtils.fromJson(resultSymbolDefinitions.polyline); - graphicSymbols.resultsSymbols.polygon = symbolUtils.fromJson(resultSymbolDefinitions.polygon); - selectionSymbolDefinitions = lang.mixin( - this.defaultSelectionSymbols, this.selectionSymbols || {} + } + }, + createResultsGrid: function () { + var Grid = declare([OnDemandGrid, Keyboard, Selection, ColumnResizer]); + this.resultsGrid = new Grid({ + selectionMode: this.selectionMode, + cellNavigation: false, + showHeader: true, + store: this.resultsStore + }, this.findResultsGrid); + this.resultsGrid.startup(); + }, + resetResultsGridColumns: function () { + if (!this.resultsGrid) { + return; + } + var columns = this.queries[this.queryIdx].gridColumns || { + layerName: 'Layer', + foundFieldName: 'Field', + value: 'Result' + }; + if (columns instanceof Array) { + columns = array.filter( + columns, function (column) { + if (typeof column.visible === 'undefined') { + column.visible = true; + } + return column.visible; + } ); - graphicSymbols.selectionSymbols = {}; - graphicSymbols.selectionSymbols.point = symbolUtils.fromJson(selectionSymbolDefinitions.point); - graphicSymbols.selectionSymbols.polyline = symbolUtils.fromJson(selectionSymbolDefinitions.polyline); - graphicSymbols.selectionSymbols.polygon = symbolUtils.fromJson(selectionSymbolDefinitions.polygon); - return graphicSymbols; - }, - parseGridColumnProperties: function () { - if (this.queries[this.queryIdx].gridColumns) { - array.forEach( - this.results, function (result) { - array.forEach( - this.queries[this.queryIdx].gridColumns, function (column) { - var shouldGetValueFromAttributes = function (column, result) { - if (column.field && !result.hasOwnProperty(column.field) && result.feature.attributes.hasOwnProperty(column.field)) { - return true; - } - return false; - }; - var shouldGetValueFromGetFunction = function (column, result) { - if (column.field && !result.hasOwnProperty(column.field) && column.get) { - return true; - } - return false; - }; - if (shouldGetValueFromAttributes(column, this)) { - this[column.field] = this.feature.attributes[column.field]; - } else if (shouldGetValueFromGetFunction(column, this)) { - this[column.field] = column.get(this); - } - }, result - ); - }, this - ); - } - }, - addResultsToGraphicsLayer: function () { - var unique = 0; + } + this.resultsGrid.setColumns(columns); + }, + resetResultsGridSort: function () { + if (!this.resultsGrid) { + return; + } + var sort = this.queries[this.queryIdx].sort || [ + { + attribute: 'value', + descending: false + } + ]; + this.resultsGrid.set('sort', sort); + }, + resetGridSelectionMode: function () { + if (!this.resultsGrid) { + return; + } + var selectionMode = this.queries[this.queryIdx].selectionMode || this.selectionMode; + this.resultsGrid.set('selectionMode', selectionMode); + }, + attachStandardEventHandlersToResultsGrid: function () { + if (!this.resultsGrid) { + return; + } + this.own( + this.resultsGrid.on('dgrid-select', lang.hitch(this, 'onResultsGridSelect')) + ); + this.own( + this.resultsGrid.on('dgrid-deselect', lang.hitch(this, 'onResultsGridDeselect')) + ); + this.own( + this.resultsGrid.on('.dgrid-row:dblclick', lang.hitch(this, 'onResultsGridRowClick')) + ); + }, + attachCustomEventHandlersToResultsGrid: function () { + if (!this.resultsGrid) { + return; + } + array.forEach(this.currentQueryEventHandlers, function (handler) { + handler.handle.remove(); + }); + var queryEventHandlers = this.queries[this.queryIdx].customGridEventHandlers || []; + array.forEach(queryEventHandlers, lang.hitch(this, function (handler) { + handler.handle = this.resultsGrid.on(handler.event, lang.hitch(this, handler.handler)); + })); + this.currentQueryEventHandlers = queryEventHandlers; + }, + showResults: function (results) { + var resultText = this.i18n.noResultsLabel; + this.results = results; + if (this.results.length > 0) { + var s = (this.results.length === 1) ? '' : this.i18n.resultsLabel.multipleResultsSuffix; + resultText = this.results.length + ' ' + this.i18n.resultsLabel.labelPrefix + s + ' ' + this.i18n.resultsLabel.labelSuffix; + this.createGraphicsLayerAndSymbols(); + this.parseGridColumnProperties(); + this.addResultsToGraphicsLayer(); + this.zoomToGraphics(this.graphicsLayer.graphics); + this.showResultsGrid(); + } + this.displayFindMessage(resultText); + }, + createGraphicsLayerAndSymbols: function () { + if (!this.graphicsLayer) { + this.graphicsLayer = this.createGraphicsLayer(); + } + if (!this.graphicsSymbols) { + this.graphicsSymbols = this.createGraphicsSymbols(); + } + }, + createGraphicsLayer: function () { + var graphicsLayer = new GraphicsLayer({ + id: this.id + '_findGraphics', + title: 'Find' + }); + graphicsLayer.on('click', lang.hitch(this, 'onGraphicsLayerClick')); + this.map.addLayer(graphicsLayer); + return graphicsLayer; + }, + onGraphicsLayerClick: function (event) { + var zoomOnSelect = this.zoomOptions.select; + this.zoomOptions.select = false; + var row = this.resultsGrid.row(event.graphic.storeid); + this.resultsGrid.select(row); + this.resultsGrid.focus(row.element); + row.element.focus(); + this.zoomOptions.select = zoomOnSelect; + }, + createGraphicsSymbols: function () { + var graphicSymbols = {}, resultSymbolDefinitions, selectionSymbolDefinitions; + resultSymbolDefinitions = lang.mixin(this.defaultResultsSymbols, this.resultsSymbols || {}); + graphicSymbols.resultsSymbols = {}; + graphicSymbols.resultsSymbols.point = symbolUtils.fromJson(resultSymbolDefinitions.point); + graphicSymbols.resultsSymbols.polyline = symbolUtils.fromJson(resultSymbolDefinitions.polyline); + graphicSymbols.resultsSymbols.polygon = symbolUtils.fromJson(resultSymbolDefinitions.polygon); + selectionSymbolDefinitions = lang.mixin( + this.defaultSelectionSymbols, this.selectionSymbols || {} + ); + graphicSymbols.selectionSymbols = {}; + graphicSymbols.selectionSymbols.point = symbolUtils.fromJson(selectionSymbolDefinitions.point); + graphicSymbols.selectionSymbols.polyline = symbolUtils.fromJson(selectionSymbolDefinitions.polyline); + graphicSymbols.selectionSymbols.polygon = symbolUtils.fromJson(selectionSymbolDefinitions.polygon); + return graphicSymbols; + }, + parseGridColumnProperties: function () { + if (this.queries[this.queryIdx].gridColumns) { array.forEach( this.results, function (result) { - result.id = unique; - result.feature.storeid = result.id; - unique++; - this.setGraphicSymbol(result.feature, false); - this.graphicsLayer.add(result.feature); + array.forEach( + this.queries[this.queryIdx].gridColumns, function (column) { + function shouldGetValueFromAttributes (col, res) { + if (col.field && !result.hasOwnProperty(col.field) && res.feature.attributes.hasOwnProperty(col.field)) { + return true; + } + return false; + } + + function shouldGetValueFromGetFunction (col, res) { + if (col.field && !res.hasOwnProperty(col.field) && col.get) { + return true; + } + return false; + } + + if (shouldGetValueFromAttributes(column, this)) { + this[column.field] = this.feature.attributes[column.field]; + } else if (shouldGetValueFromGetFunction (column, this)) { + this[column.field] = column.get(this); + } + }, result + ); }, this ); - }, - showResultsGrid: function () { - var queryInput = this.getQueryInput(); - this.resultsGrid.store.setData(this.results); - this.resultsGrid.refresh(); - var lyrDisplay = 'block'; - if (queryInput.query.layerIds.length === 1) { - lyrDisplay = 'none'; - } - this.resultsGrid.styleColumn('layerName', 'display:' + lyrDisplay); - if (queryInput.query && queryInput.query.hideGrid !== true) { - this.findResultsGrid.style.display = 'block'; - } - }, - onResultsGridSelect: function (event) { - array.forEach( - event.rows, lang.hitch( - this, function (row) { - var feature = row.data.feature; - this.setGraphicSymbol(feature, true); - if (feature && feature.getDojoShape()) { - feature.getDojoShape().moveToFront(); - } - } - ) - ); - this.graphicsLayer.redraw(); - if (this.zoomOptions.select) { - this.zoomToSelectedGraphics(); - } - }, - onResultsGridDeselect: function (event) { - array.forEach( - event.rows, lang.hitch( - this, function (row) { - var feature = row.data.feature; - this.setGraphicSymbol(feature, false); + } + }, + addResultsToGraphicsLayer: function () { + var unique = 0; + array.forEach( + this.results, function (result) { + result.id = unique; + result.feature.storeid = result.id; + unique++; + this.setGraphicSymbol(result.feature, false); + this.graphicsLayer.add(result.feature); + }, this + ); + }, + showResultsGrid: function () { + var queryInput = this.getQueryInput(); + this.resultsGrid.store.setData(this.results); + this.resultsGrid.refresh(); + var lyrDisplay = 'block'; + if (queryInput.query.layerIds.length === 1) { + lyrDisplay = 'none'; + } + this.resultsGrid.styleColumn('layerName', 'display:' + lyrDisplay); + if (queryInput.query && queryInput.query.hideGrid !== true) { + this.findResultsGrid.style.display = 'block'; + } + }, + onResultsGridSelect: function (event) { + array.forEach( + event.rows, lang.hitch( + this, function (row) { + var feature = row.data.feature; + this.setGraphicSymbol(feature, true); + if (feature && feature.getDojoShape()) { + feature.getDojoShape().moveToFront(); } - ) - ); - this.graphicsLayer.redraw(); - if (this.zoomOptions.deselect) { - this.zoomToSelectedGraphics(); - } - }, - onResultsGridRowClick: function (event) { - var row = this.resultsGrid.row(event); - var feature = row.data.feature; - setTimeout(lang.hitch(this, function () { - if (this.resultsGrid.selection.hasOwnProperty(row.id)) { - this.zoomToGraphics([feature]); } - }), 100); - }, - setGraphicSymbol: function (graphic, isSelected) { - var symbol = isSelected ? this.graphicsSymbols.selectionSymbols[graphic.geometry.type] : this.graphicsSymbols.resultsSymbols[graphic.geometry.type]; - graphic.setSymbol(symbol); - }, - zoomToSelectedGraphics: function () { - var selectedGraphics = []; - var selection = this.resultsGrid.selection; - for (var id in selection) { - if (selection.hasOwnProperty(id)) { - selectedGraphics.push(this.resultsGrid.row(id).data.feature); - } - } - if (selectedGraphics.length === 0) { - return; - } - this.zoomToGraphics(selectedGraphics); - }, - zoomToGraphics: function (graphics) { - var zoomExtent = null; - if (graphics.length > 1) { - zoomExtent = graphicsUtils.graphicsExtent(graphics); - } else if (graphics.length === 1) { - zoomExtent = this.getExtentFromGraphic(graphics[0]); - } - if (zoomExtent) { - this.setMapExtent(zoomExtent); - } - }, - getExtentFromGraphic: function (graphic) { - var extent = null; - switch (graphic.geometry.type) { - case 'point': - extent = this.getExtentFromPoint(graphic); - break; - default: - extent = graphicsUtils.graphicsExtent([graphic]); - break; - } - return extent; - }, - getExtentFromPoint: function (point) { - var sz = this.pointExtentSize; // hack - var pointGeometry = point.geometry; - return new Extent({ - 'xmin': pointGeometry.x - sz, - 'ymin': pointGeometry.y - sz, - 'xmax': pointGeometry.x + sz, - 'ymax': pointGeometry.y + sz, - 'spatialReference': { - wkid: this.spatialReference + ) + ); + this.graphicsLayer.redraw(); + if (this.zoomOptions.select) { + this.zoomToSelectedGraphics(); + } + }, + onResultsGridDeselect: function (event) { + array.forEach( + event.rows, lang.hitch( + this, function (row) { + var feature = row.data.feature; + this.setGraphicSymbol(feature, false); } - }); - }, - setMapExtent: function (extent) { - this.map.setExtent(extent.expand(this.zoomExtentFactor)); - }, - clearResults: function () { - this.results = null; - this.clearResultsGrid(); - this.clearFeatures(); - this.searchFormDijit.reset(); - this.querySelectDijit.setValue(this.queryIdx); - domConstruct.empty(this.findResultsNode); - }, - clearResultsGrid: function () { - if (this.resultStore) { - this.resultsStore.setData([]); - } - if (this.resultsGrid) { - this.resultsGrid.refresh(); - } - this.findResultsNode.style.display = 'none'; - this.findResultsGrid.style.display = 'none'; - }, - clearFeatures: function () { - if (this.graphicsLayer) { - this.graphicsLayer.clear(); + ) + ); + this.graphicsLayer.redraw(); + if (this.zoomOptions.deselect) { + this.zoomToSelectedGraphics(); + } + }, + onResultsGridRowClick: function (event) { + var row = this.resultsGrid.row(event); + var feature = row.data.feature; + setTimeout(lang.hitch(this, function () { + if (this.resultsGrid.selection.hasOwnProperty(row.id)) { + this.zoomToGraphics([feature]); + } + }), 100); + }, + setGraphicSymbol: function (graphic, isSelected) { + var symbol = isSelected ? this.graphicsSymbols.selectionSymbols[graphic.geometry.type] : this.graphicsSymbols.resultsSymbols[graphic.geometry.type]; + graphic.setSymbol(symbol); + }, + zoomToSelectedGraphics: function () { + var selectedGraphics = []; + var selection = this.resultsGrid.selection; + for (var id in selection) { + if (selection.hasOwnProperty(id)) { + selectedGraphics.push(this.resultsGrid.row(id).data.feature); } - }, - _onQueryChange: function (queryIdx) { - if (queryIdx >= 0 && queryIdx < this.queries.length) { - this.queryIdx = queryIdx; - this.updateSearchPrompt(); + } + if (selectedGraphics.length === 0) { + return; + } + this.zoomToGraphics(selectedGraphics); + }, + zoomToGraphics: function (graphics) { + var zoomExtent = null; + if (graphics.length > 1) { + zoomExtent = graphicsUtils.graphicsExtent(graphics); + } else if (graphics.length === 1) { + zoomExtent = this.getExtentFromGraphic(graphics[0]); + } + if (zoomExtent) { + this.setMapExtent(zoomExtent); + } + }, + getExtentFromGraphic: function (graphic) { + var extent = null; + switch (graphic.geometry.type) { + case 'point': + extent = this.getExtentFromPoint(graphic); + break; + default: + extent = graphicsUtils.graphicsExtent([graphic]); + break; + } + return extent; + }, + getExtentFromPoint: function (point) { + var sz = this.pointExtentSize; // hack + var pointGeometry = point.geometry; + return new Extent({ + 'xmin': pointGeometry.x - sz, + 'ymin': pointGeometry.y - sz, + 'xmax': pointGeometry.x + sz, + 'ymax': pointGeometry.y + sz, + 'spatialReference': { + wkid: this.spatialReference } - }, - updateSearchPrompt: function () { - var prompt = this.queries[this.queryIdx].prompt || i18n.searchText.placeholder; - this.searchTextDijit.set('placeholder', prompt); - this.searchTextDijit.set('value', null); - }, - onZoomOptionsSelectChange: function (value) { - this.zoomOptions.select = value; - }, - onZoomOptionsDeselectChange: function (value) { - this.zoomOptions.deselect = value; + }); + }, + setMapExtent: function (extent) { + this.map.setExtent(extent.expand(this.zoomExtentFactor)); + }, + clearResults: function () { + this.results = null; + this.clearResultsGrid(); + this.clearFeatures(); + this.searchFormDijit.reset(); + this.querySelectDijit.setValue(this.queryIdx); + domConstruct.empty(this.findResultsNode); + }, + clearResultsGrid: function () { + if (this.resultStore) { + this.resultsStore.setData([]); + } + if (this.resultsGrid) { + this.resultsGrid.refresh(); + } + this.findResultsNode.style.display = 'none'; + this.findResultsGrid.style.display = 'none'; + }, + clearFeatures: function () { + if (this.graphicsLayer) { + this.graphicsLayer.clear(); + } + }, + _onQueryChange: function (queryIdx) { + if (queryIdx >= 0 && queryIdx < this.queries.length) { + this.queryIdx = queryIdx; + this.updateSearchPrompt(); } + }, + updateSearchPrompt: function () { + var prompt = this.queries[this.queryIdx].prompt || i18n.searchText.placeholder; + this.searchTextDijit.set('placeholder', prompt); + this.searchTextDijit.set('value', null); + }, + onZoomOptionsSelectChange: function (value) { + this.zoomOptions.select = value; + }, + onZoomOptionsDeselectChange: function (value) { + this.zoomOptions.deselect = value; } - ); - } -); \ No newline at end of file + } + ); +}); diff --git a/viewer/js/gis/dijit/Find/nls/es/resource.js b/viewer/js/gis/dijit/Find/nls/es/resource.js new file mode 100644 index 000000000..0efc73504 --- /dev/null +++ b/viewer/js/gis/dijit/Find/nls/es/resource.js @@ -0,0 +1,25 @@ +define ({ + selectQuery: 'Consulta de selección', + searchText: { + label: 'Buscar', + placeholder: 'Introduzca el texto que desea buscar.' + }, + exactMatches: 'Buscar sólo coincidencias exactas', + searchButton: { + label: 'Buscar', + busyLabel: 'buscando' + }, + clearButton: { + label: 'Despejar' + }, + searching: 'Buscando...', + resultsLabel: { + multipleResultsSuffix: 's', + labelPrefix: 'Resultado', + labelSuffix: 'encontró' + }, + noResultsLabel: 'No se han encontrado resultados.', + optionsLabel: 'Opciones', + zoomOnSelect: 'Ampliar en seleccione', + zoomOnDeselect: 'Ampliar en no seleccione' +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Find/nls/fr/resource.js b/viewer/js/gis/dijit/Find/nls/fr/resource.js new file mode 100644 index 000000000..63dfd8680 --- /dev/null +++ b/viewer/js/gis/dijit/Find/nls/fr/resource.js @@ -0,0 +1,25 @@ +define ({ + selectQuery: 'Sélection', + searchText: { + label: 'Rechercher', + placeholder: 'Entrez le texte que vous souhaitez rechercher.' + }, + exactMatches: 'Correspondances exactes seulement', + searchButton: { + label: 'Rechercher', + busyLabel: 'recherche' + }, + clearButton: { + label: 'Effacer' + }, + searching: 'Recherche...', + resultsLabel: { + multipleResultsSuffix: 's', + labelPrefix: 'Résultat', + labelSuffix: 'Trouvé' + }, + noResultsLabel: 'Aucun résultat', + optionsLabel: 'Options', + zoomOnSelect: 'Zoom sur la sélection', + zoomOnDeselect: 'Zoom en desélectionnant' +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Find/nls/pt-br/resource.js b/viewer/js/gis/dijit/Find/nls/pt-br/resource.js new file mode 100644 index 000000000..fa350b994 --- /dev/null +++ b/viewer/js/gis/dijit/Find/nls/pt-br/resource.js @@ -0,0 +1,26 @@ +// http://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html +define({ + selectQuery: 'Selecionar Procura', + searchText: { + label: 'Procurar por', + placeholder: 'Digite o texto que você quer procurar.' + }, + exactMatches: 'Apenas buscas exatas', + searchButton: { + label: 'Procurar', + busyLabel: 'procurando' + }, + clearButton: { + label: 'Limpar' + }, + searching: 'Procurando...', + resultsLabel: { + multipleResultsSuffix: 's', + labelPrefix: 'Resultado', + labelSuffix: 'encontrado' + }, + noResultsLabel: 'Nenhum Resultado Encontrado.', + optionsLabel: 'Opções', + zoomOnSelect: 'Zoom para selecionar', + zoomOnDeselect: 'Zoom para deselecionar' +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Find/nls/pt-pt/resource.js b/viewer/js/gis/dijit/Find/nls/pt-pt/resource.js new file mode 100644 index 000000000..e38f69d21 --- /dev/null +++ b/viewer/js/gis/dijit/Find/nls/pt-pt/resource.js @@ -0,0 +1,26 @@ +// http://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html +define({ + selectQuery: 'Seleccionar consulta', + searchText: { + label: 'Procurar por', + placeholder: 'Introduza o texto que pretende procurar.' + }, + exactMatches: 'Apenas correspondências exactas', + searchButton: { + label: 'Procurar', + busyLabel: 'a procurar' + }, + clearButton: { + label: 'Limpar' + }, + searching: 'A procurar...', + resultsLabel: { + multipleResultsSuffix: 's', + labelPrefix: 'Resultado', + labelSuffix: 'encontrado' + }, + noResultsLabel: 'Nenhum resultado encontrado.', + optionsLabel: 'Opções', + zoomOnSelect: 'Aproximar ao seleccionar', + zoomOnDeselect: 'Aproximar ao desseleccionar' +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Find/nls/resource.js b/viewer/js/gis/dijit/Find/nls/resource.js index 395533c06..4e0a71f8d 100644 --- a/viewer/js/gis/dijit/Find/nls/resource.js +++ b/viewer/js/gis/dijit/Find/nls/resource.js @@ -1,29 +1,33 @@ -// http://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html +// https://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html define({ - root: { - selectQuery: 'Select query', - searchText: { - label: 'Search for', - placeholder: 'Enter the text you want to search for.' - }, - exactMatches: 'Find exact matches only', - searchButton: { - label: 'Search', - busyLabel: 'searching' - }, - clearButton: { - label: 'Clear' - }, - searching: 'Searching...', - resultsLabel: { - multipleResultsSuffix: 's', - labelPrefix: 'Result', - labelSuffix: 'found' - }, - noResultsLabel: 'No results found.', - optionsLabel: 'Options', - zoomOnSelect: 'Zoom on select', - zoomOnDeselect: 'Zoom on deselect' - } + root: { + selectQuery: 'Select query', + searchText: { + label: 'Search for', + placeholder: 'Enter the text you want to search for.' + }, + exactMatches: 'Find exact matches only', + searchButton: { + label: 'Search', + busyLabel: 'searching' + }, + clearButton: { + label: 'Clear' + }, + searching: 'Searching...', + resultsLabel: { + multipleResultsSuffix: 's', + labelPrefix: 'Result', + labelSuffix: 'found' + }, + noResultsLabel: 'No results found.', + optionsLabel: 'Options', + zoomOnSelect: 'Zoom on select', + zoomOnDeselect: 'Zoom on deselect' + }, + 'es': true, + 'fr': true, + 'pt-br': true, + 'pt-pt': true }); diff --git a/viewer/js/gis/dijit/FloatingTitlePane.js b/viewer/js/gis/dijit/FloatingTitlePane.js index 6963190bb..6c9e05c16 100644 --- a/viewer/js/gis/dijit/FloatingTitlePane.js +++ b/viewer/js/gis/dijit/FloatingTitlePane.js @@ -6,6 +6,7 @@ define([ 'dojo/dnd/Moveable', 'dojo/aspect', 'dojo/topic', + 'dojo/sniff', 'dojo/_base/window', 'dojo/window', 'dojo/dom-geometry', @@ -13,15 +14,33 @@ define([ 'dojo/dom-construct', 'dojo/dom-attr', 'dojo/dom-class', + 'dojox/layout/ResizeHandle', + 'xstyle/css!dojox/layout/resources/ResizeHandle.css', 'xstyle/css!./FloatingTitlePane/css/FloatingTitlePane.css' -], function (declare, TitlePane, on, lang, Moveable, aspect, topic, win, winUtils, domGeom, domStyle, domConstruct, domAttr, domClass) { +], function (declare, TitlePane, on, lang, Moveable, aspect, topic, has, win, winUtils, domGeom, domStyle, domConstruct, domAttr, domClass, ResizeHandle) { + return declare([TitlePane], { sidebarPosition: null, + + canFloat: false, + isFloating: false, + isDragging: false, + dragDelay: 3, + + resizable: false, + resizeOptions: {}, + isResizing: false, + postCreate: function () { if (this.canFloat) { this.createDomNodes(); this.own(on(window, 'resize', lang.hitch(this, '_endDrag'))); } + if (this.iconClass) { + this.iconNode = domConstruct.create('span', { + 'class': 'titlePaneIcon fa fa-fw ' + this.iconClass + }, this.titleNode, 'before'); + } this.own(topic.subscribe('titlePane/event', lang.hitch(this, '_updateWidgetSidebarPosition'))); this.own(aspect.after(this, 'toggle', lang.hitch(this, '_afterToggle'))); this.inherited(arguments); @@ -29,13 +48,21 @@ define([ startup: function () { if (this.titleBarNode && this.canFloat) { this._moveable = new Moveable(this.domNode, { - delay: 5, - handle: this.titleBarNode + handle: this.titleBarNode, + delay: this.dragDelay }); + if (this.dragDelay > 0) { + this._moveable.mover.prototype.onMouseUp = function (e) { + this.destroy(); + e.preventDefault(); + e.stopPropagation(); + }; + } + this._titleBarHeight = domStyle.get(this.titleBarNode, 'height'); aspect.after(this._moveable, 'onMove', lang.hitch(this, '_dragging'), true); aspect.after(this._moveable, 'onMoveStop', lang.hitch(this, '_endDrag'), true); aspect.after(this._moveable, 'onMoveStart', lang.hitch(this, '_startDrag'), true); - + // ensure that dragging the movable stops no matter // when/where the mouse is released or a touch is completed on(document, 'mouseup, touchend', lang.hitch(this, '_endDrag')); @@ -57,36 +84,42 @@ define([ this._dockWidget(); evt.stopImmediatePropagation(); }))); + + if (this.resizable) { + var resOptions = lang.mixin({ + targetId: this.id, + activeResize: true, + intermediateChanges: true, + startTopic: this.id + '/resize/start', + endTopic: this.id + '/resize/end' + }, this.resizeOptions); + this._resizer = new ResizeHandle(resOptions).placeAt(this.id); + domStyle.set(this._resizer.resizeHandle, 'display', 'none'); + on(this._resizer, 'resize', lang.hitch(this, '_resizing'), true); + this.own(topic.subscribe(this.id + '/resize/start', lang.hitch(this, '_startResize'))); + this.own(topic.subscribe(this.id + '/resize/end', lang.hitch(this, '_endResize'))); + } }, + + /* Methods related to Toggling the TitleBar */ toggle: function () { - if (this.isFloating && this.isDragging) { + if ((this.isFloating && this.isDragging) || this.resizing) { return; } this.inherited(arguments); }, - _dockWidget: function () { - if (!this.isDragging) { - domAttr.remove(this.domNode, 'style'); - domStyle.set(this.dockHandleNode, 'display', 'none'); - domStyle.set(this.moveHandleNode, 'display', 'inline'); - var dockedWidgets = this.sidebar.getChildren(); - if (this.sidebarPosition > dockedWidgets.length || this.sidebarPosition < 0) { - this.sidebarPosition = dockedWidgets.length; - } - this.placeAt(this.sidebar, this.sidebarPosition); - this.isFloating = false; - this._updateTopic('dock'); - } + _afterToggle: function () { + var evt = this.open ? 'open' : 'close'; + this._updateTopic(evt); }, + + /* Methods for Dragging */ _dragging: function () { this.isDragging = true; - }, - _startDrag: function (mover) { if (!this.titleCursor) { this.titleCursor = domStyle.get(this.titleBarNode, 'cursor'); } domStyle.set(this.titleBarNode, 'cursor', 'move'); - if (!this.isFloating) { this._checkSidebarPosition(); domStyle.set(this.dockHandleNode, 'display', 'inline'); @@ -99,13 +132,19 @@ define([ }, computedStyle); this.isFloating = true; this.placeAt(win.body()); - var titleHeight = domStyle.get(this.titleBarNode, 'height'); domStyle.set(this.domNode, { - top: (mover.marginBox.t - titleHeight) + 'px' + top: (this._moverBox.t - this._titleBarHeight) + 'px' }); + + if (this.resizable && this._resizer && this._resizer.resizeHandle) { + domStyle.set(this._resizer.resizeHandle, 'display', 'block'); + } this._updateTopic('undock'); } }, + _startDrag: function (mover) { + this._moverBox = mover.marginBox; + }, _endDrag: function () { // summary: // Called after dragging the Dialog. Saves the position of the dialog in the viewport, @@ -142,6 +181,28 @@ define([ }); } }, + + /* Methods for Docking and Undocking */ + _dockWidget: function () { + if (!this.isDragging) { + domAttr.remove(this.domNode, 'style'); + domStyle.set(this.dockHandleNode, 'display', 'none'); + domStyle.set(this.moveHandleNode, 'display', 'inline'); + var dockedWidgets = this.sidebar.getChildren(); + if (this.sidebarPosition > dockedWidgets.length || this.sidebarPosition < 0) { + this.sidebarPosition = dockedWidgets.length; + } + this.placeAt(this.sidebar, this.sidebarPosition); + this.isFloating = false; + this._updateTopic('dock'); + } + if (this.resizable && this._resizer && this._resizer.resizeHandle) { + domStyle.set(this._resizer.resizeHandle, 'display', 'none'); + if (this._initialDimensions) { + topic.publish(this.id + '/resize/resize', this._initialDimensions); + } + } + }, _updateWidgetSidebarPosition: function (msg) { var id = msg.widgetID, pos = msg.sidebarPosition, action = msg.action; @@ -185,6 +246,30 @@ define([ } } }, + + /* Methods for Resizing */ + _resizing: function (evt) { + this.isResizing = true; + var newDim = this._resizer._getNewCoords(evt, this, 'margin'); + if (newDim) { + topic.publish(this.id + '/resize/resize', { + h: this._resizeDimensions.h + (newDim.h - this._resizer.startSize.h), + w: this._resizeDimensions.w + (newDim.w - this._resizer.startSize.w) + }); + } + }, + _startResize: function () { + this.isResizing = true; + this._resizeDimensions = domGeom.getContentBox(this.containerNode); + if (!this._initialDimensions) { + this._initialDimensions = this._resizeDimensions; + } + }, + _endResize: function () { + this.isResizing = false; + domStyle.set(this.domNode, 'height', 'auto'); + }, + _updateTopic: function (msg) { topic.publish('titlePane/event', { category: 'Titlepane Event', @@ -194,10 +279,6 @@ define([ sidebarPosition: this.sidebarPosition, value: msg }); - }, - _afterToggle: function () { - var evt = this.open ? 'open' : 'close'; - this._updateTopic(evt); } }); }); \ No newline at end of file diff --git a/viewer/js/gis/dijit/FloatingWidgetDialog.js b/viewer/js/gis/dijit/FloatingWidgetDialog.js index 7979e76d4..42a0170fa 100644 --- a/viewer/js/gis/dijit/FloatingWidgetDialog.js +++ b/viewer/js/gis/dijit/FloatingWidgetDialog.js @@ -1,15 +1,16 @@ define([ - 'dojo/_base/declare', - 'dijit/Dialog' + 'dojo/_base/declare', + 'dijit/Dialog' ], function (declare, Dialog) { - return declare([Dialog], { - declaredClass: 'gis.dijit.FloatingWidget', - title: 'Floating Widget', - draggable: true, - 'class': 'floatingWidget', - close: function () { - this.hide(); - }, - focus: function () {} - }); + + return declare([Dialog], { + declaredClass: 'gis.dijit.FloatingWidget', + title: 'Floating Widget', + draggable: true, + 'class': 'floatingWidget', + close: function () { + this.hide(); + }, + focus: function () {} + }); }); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Geocoder.js b/viewer/js/gis/dijit/Geocoder.js index 694b18d7d..b21a9d8fb 100644 --- a/viewer/js/gis/dijit/Geocoder.js +++ b/viewer/js/gis/dijit/Geocoder.js @@ -19,6 +19,7 @@ define([ 'xstyle/css!./Geocoder/css/Geocoder.css' ], function (declare, _WidgetBase, _TemplatedMixin, a11yclick, lang, on, domClass, domStyle, Geocoder, MenuItem, SimpleMarkerSymbol, Graphic, InfoTemplate, GraphicsLayer, template, i18n) { + return declare([_WidgetBase, _TemplatedMixin], { templateString: template, i18n: i18n, @@ -127,6 +128,7 @@ define([ this.map.infoWindow.clearFeatures(); this.map.infoWindow.setTitle(graphic.getTitle()); this.map.infoWindow.setContent(graphic.getContent()); + this.map.infoWindow.setFeatures([graphic]); var screenPnt = this.map.toScreen(res.location); this.map.infoWindow.show(screenPnt, this.map.getInfoWindowAnchor(screenPnt)); diff --git a/viewer/js/gis/dijit/Geocoder/nls/es/resource.js b/viewer/js/gis/dijit/Geocoder/nls/es/resource.js new file mode 100644 index 000000000..edd0ec207 --- /dev/null +++ b/viewer/js/gis/dijit/Geocoder/nls/es/resource.js @@ -0,0 +1,14 @@ +define ({ + title: 'Alternar barra de búsqueda', + labels: { + address: 'Dirección', + neighborhood: 'Barrio', + city: 'Ciudad', + subregion: 'Subregión', + region: 'Región', + postalCode: 'Código postal', + countryCode: 'Código de país', + locatorName: 'Nombre del localizador', + getAddressHere: 'Obtener dirección aquí' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Geocoder/nls/fr/resource.js b/viewer/js/gis/dijit/Geocoder/nls/fr/resource.js new file mode 100644 index 000000000..8d4e233f8 --- /dev/null +++ b/viewer/js/gis/dijit/Geocoder/nls/fr/resource.js @@ -0,0 +1,14 @@ +define ({ + title: 'Activer/désactiver la barre de recherche', + labels: { + address: 'Adresse', + neighborhood: 'Quartier', + city: 'Ville', + subregion: 'Sous-région', + region: 'Région', + postalCode: 'Code postal', + countryCode: 'Code de pays', + locatorName: 'Nom du localisateur', + getAddressHere: 'Obtenir l\'adresse ici' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Geocoder/nls/pt-br/resource.js b/viewer/js/gis/dijit/Geocoder/nls/pt-br/resource.js new file mode 100644 index 000000000..8f79694a2 --- /dev/null +++ b/viewer/js/gis/dijit/Geocoder/nls/pt-br/resource.js @@ -0,0 +1,14 @@ +define ({ + title: 'Alternar barra de Pesquisa', + labels: { + address: 'Endereço', + neighborhood: 'Bairro', + city: 'Cidade', + subregion: 'Subregião', + region: 'Região', + postalCode: 'Código Postal (CEP)', + countryCode: 'Código do País', + locatorName: 'Nome do Localizador', + getAddressHere: 'Obtenha o Endereço daqui' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Geocoder/nls/pt-pt/resource.js b/viewer/js/gis/dijit/Geocoder/nls/pt-pt/resource.js new file mode 100644 index 000000000..7667ddf08 --- /dev/null +++ b/viewer/js/gis/dijit/Geocoder/nls/pt-pt/resource.js @@ -0,0 +1,14 @@ +define({ + title: 'Alternar barra de pesquisa', + labels: { + address: 'Endereço', + neighborhood: 'Bairro', + city: 'Cidade', + subregion: 'Subregião', + region: 'Região', + postalCode: 'Código postal', + countryCode: 'Código do país', + locatorName: 'Nome do localizador', + getAddressHere: 'Obter o endereço daqui' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Geocoder/nls/resource.js b/viewer/js/gis/dijit/Geocoder/nls/resource.js index 5f02f504a..a93722458 100644 --- a/viewer/js/gis/dijit/Geocoder/nls/resource.js +++ b/viewer/js/gis/dijit/Geocoder/nls/resource.js @@ -12,5 +12,9 @@ define ({ locatorName: 'Locator name', getAddressHere: 'Get address here' } - } + }, + 'es': true, + 'fr': true, + 'pt-br': true, + 'pt-pt': true }); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Growler.js b/viewer/js/gis/dijit/Growler.js index 732342808..8c5b948b4 100644 --- a/viewer/js/gis/dijit/Growler.js +++ b/viewer/js/gis/dijit/Growler.js @@ -11,23 +11,6 @@ define([ 'xstyle/css!./Growler/css/Growler.css' ], function (declare, _WidgetBase, _TemplatedMixin, lang, Style, domConstruct, fx, domClass, topic) { - // main growler dijit container - var Growler = declare([_WidgetBase, _TemplatedMixin], { - templateString: '
', - postCreate: function () { - this.inherited(arguments); - this.own(topic.subscribe('growler/growl', lang.hitch(this, 'growl'))); - }, - growl: function (props) { - props = props || {}; - lang.mixin(props, { - _container: this.containerNode - }); - var g = new Growl(props); - g.startup(); - } - }); - // the growl itself var Growl = declare([_WidgetBase, _TemplatedMixin], { templateString: '

${title}

', @@ -82,5 +65,23 @@ define([ }, 250, null, lang.partial(domConstruct.destroy, this.domNode)); } }); + + // main growler dijit container + var Growler = declare([_WidgetBase, _TemplatedMixin], { + templateString: '
', + postCreate: function () { + this.inherited(arguments); + this.own(topic.subscribe('growler/growl', lang.hitch(this, 'growl'))); + }, + growl: function (props) { + props = props || {}; + lang.mixin(props, { + _container: this.containerNode + }); + var g = new Growl(props); + g.startup(); + } + }); + return Growler; }); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Help.js b/viewer/js/gis/dijit/Help.js index 2e605fecc..461a374d1 100644 --- a/viewer/js/gis/dijit/Help.js +++ b/viewer/js/gis/dijit/Help.js @@ -1,5 +1,5 @@ define([ - 'dojo/_base/declare', + 'dojo/_base/declare', 'dijit/_WidgetBase', 'dijit/_TemplatedMixin', 'dijit/_WidgetsInTemplateMixin', @@ -8,45 +8,46 @@ define([ 'dojo/on', 'dojo/_base/lang', 'dojo/aspect', - 'dojo/text!./Help/templates/HelpDialog.html', + 'dojo/text!./Help/templates/HelpDialog.html', + 'dojo/i18n!./Help/nls/resource', 'dijit/form/Button', - 'dijit/layout/TabContainer', - 'dijit/layout/ContentPane', - 'xstyle/css!./Help/css/Help.css' -], function (declare, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, _FloatingWidgetMixin, domConstruct, on, lang, aspect, template) { + 'dijit/layout/TabContainer', + 'dijit/layout/ContentPane', + 'xstyle/css!./Help/css/Help.css' +], function (declare, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, _FloatingWidgetMixin, domConstruct, on, lang, aspect, template, i18n) { - return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, _FloatingWidgetMixin], { - widgetsInTemplate: true, - templateString: template, - title: 'Help', - html: 'Help', - domTarget: 'helpDijit', - draggable: false, - baseClass: 'helpDijit', - postCreate: function () { - this.inherited(arguments); - this.parentWidget.draggable = this.draggable; - if (this.parentWidget.toggleable) { - this.own(aspect.after(this.parentWidget, 'toggle', lang.hitch(this, function () { - this.containerNode.resize(); - }))); - } else { - var help = domConstruct.place(this.html, this.domTarget); - on(help, 'click', lang.hitch(this.parentWidget, 'show')); - } - }, - onOpen: function () { - // Make sure the content is visible when the dialog - // is shown/opened. Something like this may be needed - // for all floating windows that don't open on startup? - if (!this.openOnStartup) { - this.containerNode.resize(); - } - }, - close: function () { - if (this.parentWidget.hide) { - this.parentWidget.hide(); - } - } - }); + return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, _FloatingWidgetMixin], { + widgetsInTemplate: true, + templateString: template, + i18n: i18n, + html: 'link'.replace('link', i18n.link), + domTarget: 'helpDijit', + draggable: false, + baseClass: 'helpDijit', + postCreate: function () { + this.inherited(arguments); + this.parentWidget.draggable = this.draggable; + if (this.parentWidget.toggleable) { + this.own(aspect.after(this.parentWidget, 'toggle', lang.hitch(this, function () { + this.containerNode.resize(); + }))); + } else { + var help = domConstruct.place(this.html, this.domTarget); + on(help, 'click', lang.hitch(this.parentWidget, 'show')); + } + }, + onOpen: function () { + // Make sure the content is visible when the dialog + // is shown/opened. Something like this may be needed + // for all floating windows that don't open on startup? + if (!this.openOnStartup) { + this.containerNode.resize(); + } + }, + close: function () { + if (this.parentWidget.hide) { + this.parentWidget.hide(); + } + } + }); }); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Help/nls/es/resource.js b/viewer/js/gis/dijit/Help/nls/es/resource.js new file mode 100644 index 000000000..6c4cea412 --- /dev/null +++ b/viewer/js/gis/dijit/Help/nls/es/resource.js @@ -0,0 +1,36 @@ +define ({ + link: 'Ayuda', + navigation: { + title: 'Navegación', + description: 'Mapa de navegación a través del ratón y el teclado:', + pan1: 'Arrastre a la sartén', + recenter: 'SHIFT + Clic para volver a centrar', + zoomIn1: 'SHIFT + Arrastre para ampliar la imagen', + zoomOut1: 'SHIFT + CTRL + arrastrar para alejarla', + zoomIn2: 'De desplazamiento del ratón hacia adelante para hacer un zoom', + zoomOut2: 'De desplazamiento del ratón hacia atrás para reducir', + pan2: 'Utilice las teclas de flecha para desplazarse', + zoomInLevel: '+ clave para hacer un zoom un nivel', + zoomOutLevel: '- clave para alejar un nivel', + zoomCenter: 'Doble click para Centro y hacer zoom in' + }, + search: { + title: 'Buscar', + description: 'Una variedad de búsquedas se pueden realizar en el buscador:', + address: 'Buscar por Dirección', + place: 'Búsqueda Territorial', + etc: 'Buscar por código postal, condado, etc.' + }, + tools: { + title: 'Herramientas', + description: 'Además de las capacidades de búsqueda, se proporcionan las siguientes herramientas:', + measure: { + title: 'Medición', + description: 'La herramienta de medida proporciona la capacidad para dibujar un punto, una línea o un polígono en el mapa y especificar la unidad de medida.' + }, + print: { + title: 'Impresión', + description: 'Este mapa se puede exportar a diversos formatos y diseños.' + } + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Help/nls/fr/resource.js b/viewer/js/gis/dijit/Help/nls/fr/resource.js new file mode 100644 index 000000000..6bda3e07f --- /dev/null +++ b/viewer/js/gis/dijit/Help/nls/fr/resource.js @@ -0,0 +1,36 @@ +define ({ + link: 'Aide', + navigation: { + title: 'Navigation', + description: 'Navigation dans la carte en utilisant la souris et le clavier:', + pan1: 'Clic + Glisser pour déplacer la carte', + recenter: 'SHIFT + Clic pour recentrer', + zoomIn1: 'SHIFT + Sélection pour agrandir', + zoomOut1: 'SHIFT + CTRL + glisser pour effectuer un zoom arrière', + zoomIn2: 'Roulette de la souris vers l\'avant pour agrandir', + zoomOut2: 'Roulette de la souris vers l\'avant pour rétrécir', + pan2: 'Utilisez les flèches pour vous déplacer', + zoomInLevel: '+ pour zoomer un niveau', + zoomOutLevel: '- pour rétrécir un niveau', + zoomCenter: 'Double cliquez pour centrer et agrandir' + }, + search: { + title: 'Recherche', + description: 'Une variété de recherches peuvent être effectuées dans la zone de recherche:', + address: 'Recherche par adresse', + place: 'Recherche par nom de lieu', + etc: 'Recherche par code postal, région, etc.' + }, + tools: { + title: 'Outils', + description: 'En plus des capacités de recherche, les outils suivants sont fournis:', + measure: { + title: 'Mesurer', + description: 'L\'outil de mesure fournit les capacités pour dessiner un point, une ligne ou un polygone sur la carte et indiquer l\'unité de mesure.' + }, + print: { + title: 'Impression', + description: 'Cette carte peut être exportée vers différents formats et mises en page.' + } + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Help/nls/pt-br/resource.js b/viewer/js/gis/dijit/Help/nls/pt-br/resource.js new file mode 100644 index 000000000..2793d85a8 --- /dev/null +++ b/viewer/js/gis/dijit/Help/nls/pt-br/resource.js @@ -0,0 +1,36 @@ +define({ + link: 'Ajuda', + navigation: { + title: 'Navegação', + description: 'Navegação no mapa usando o rato e o teclado', + pan1: 'Arrastar para mover', + recenter: 'SHIFT + Clique para centrar', + zoomIn1: 'SHIFT + Arrastar para aproximar à área', + zoomOut1: 'SHIFT + CTRL + Arrastar para afastar', + zoomIn2: 'Mover roda de deslocação do rato para a frente para aproximar', + zoomOut2: 'Mover roda de deslocação do rato para trás para afastar', + pan2: 'Teclas de seta para mover', + zoomInLevel: 'Tecla + para aproximar um nível', + zoomOutLevel: 'Tecla - para afastar um nível', + zoomCenter: 'Duplo clique para centrar e aproximar' + }, + search: { + title: 'Pesquisa', + description: 'A caixa de pesquisa suporta vários tipos de pesquisa:', + address: 'Pesquisar por endereço', + place: 'Pesquisar por nome do local', + etc: 'Pesquisar por código postal, região, etc.' + }, + tools: { + title: 'Ferramentas', + description: 'Além das funcionalidades de pesquisa, são incluídas as seguintes ferramentas:', + measure: { + title: 'Medir', + description: 'A ferramenta de medição permite desenhar um ponto, linha, ou polígono, no mapa e especificar a unidade de medida.' + }, + print: { + title: 'Imprimir', + description: 'Este mapa pode ser exportado para diferentes formatos e modelos.' + } + } +}); diff --git a/viewer/js/gis/dijit/Help/nls/pt-pt/resource.js b/viewer/js/gis/dijit/Help/nls/pt-pt/resource.js new file mode 100644 index 000000000..2793d85a8 --- /dev/null +++ b/viewer/js/gis/dijit/Help/nls/pt-pt/resource.js @@ -0,0 +1,36 @@ +define({ + link: 'Ajuda', + navigation: { + title: 'Navegação', + description: 'Navegação no mapa usando o rato e o teclado', + pan1: 'Arrastar para mover', + recenter: 'SHIFT + Clique para centrar', + zoomIn1: 'SHIFT + Arrastar para aproximar à área', + zoomOut1: 'SHIFT + CTRL + Arrastar para afastar', + zoomIn2: 'Mover roda de deslocação do rato para a frente para aproximar', + zoomOut2: 'Mover roda de deslocação do rato para trás para afastar', + pan2: 'Teclas de seta para mover', + zoomInLevel: 'Tecla + para aproximar um nível', + zoomOutLevel: 'Tecla - para afastar um nível', + zoomCenter: 'Duplo clique para centrar e aproximar' + }, + search: { + title: 'Pesquisa', + description: 'A caixa de pesquisa suporta vários tipos de pesquisa:', + address: 'Pesquisar por endereço', + place: 'Pesquisar por nome do local', + etc: 'Pesquisar por código postal, região, etc.' + }, + tools: { + title: 'Ferramentas', + description: 'Além das funcionalidades de pesquisa, são incluídas as seguintes ferramentas:', + measure: { + title: 'Medir', + description: 'A ferramenta de medição permite desenhar um ponto, linha, ou polígono, no mapa e especificar a unidade de medida.' + }, + print: { + title: 'Imprimir', + description: 'Este mapa pode ser exportado para diferentes formatos e modelos.' + } + } +}); diff --git a/viewer/js/gis/dijit/Help/nls/resource.js b/viewer/js/gis/dijit/Help/nls/resource.js new file mode 100644 index 000000000..137c491ff --- /dev/null +++ b/viewer/js/gis/dijit/Help/nls/resource.js @@ -0,0 +1,42 @@ +define({ + root: { + link: 'Help', + navigation: { + title: 'Navigation', + description: 'Map navigation using mouse and keyboard:', + pan1: 'Drag to pan', + recenter: 'SHIFT + Click to recenter', + zoomIn1: 'SHIFT + Drag to zoom in', + zoomOut1: 'SHIFT + CTRL + Drag to zoom out', + zoomIn2: 'Mouse Scroll Forward to zoom in', + zoomOut2: 'Mouse Scroll Backward to zoom out', + pan2: 'Use Arrow keys to pan', + zoomInLevel: '+ key to zoom in a level', + zoomOutLevel: '- key to zoom out a level', + zoomCenter: 'Double Click to Center and Zoom in' + }, + search: { + title: 'Search', + description: 'A variety of searches can be performed in the search box:', + address: 'Search by Address', + place: 'Search by Place Name', + etc: 'Search By Zip Code, County, etc.' + }, + tools: { + title: 'Tools', + description: 'In addition to Search capabilities, the following tools are provided:', + measure: { + title: 'Measure', + description: 'The measure tool provides the capabilities to draw a point, line, or polygon on the map and specify the unit of measurement.' + }, + print: { + title: 'Print', + description: 'This map can be exported to various formats and layouts.' + } + } + }, + 'es': true, + 'fr': true, + 'pt-br': true, + 'pt-pt': true +}); diff --git a/viewer/js/gis/dijit/Help/templates/HelpDialog.html b/viewer/js/gis/dijit/Help/templates/HelpDialog.html index 82a31e5b9..da701f42f 100644 --- a/viewer/js/gis/dijit/Help/templates/HelpDialog.html +++ b/viewer/js/gis/dijit/Help/templates/HelpDialog.html @@ -2,42 +2,42 @@
-
+
@@ -45,35 +45,34 @@
- Map navigation using mouse and keyboard: + ${i18n.navigation.description}
  • - Drag to pan + ${i18n.navigation.pan1}
  • - SHIFT + Click to recenter + ${i18n.navigation.recenter}
  • - SHIFT + Drag to zoom in + ${i18n.navigation.zoomIn1}
  • - SHIFT + CTRL + Drag to zoom out + ${i18n.navigation.zoomOut1}
  • - Mouse Scroll Forward to zoom in + ${i18n.navigation.zoomIn2}
  • - Mouse Scroll Backward to zoom out + ${i18n.navigation.zoomOut2}
  • - Use Arrow keys to pan + ${i18n.navigation.pan2}
  • - + key to zoom in a level + ${i18n.navigation.zoomInLevel}
  • - - key to zoom out a level + ${i18n.navigation.zoomOutLevel}
  • - Double Click to Center and Zoom in + ${i18n.navigation.zoomCenter}
-
- A variety of searches can be performed in the search box: +
+ ${i18n.search.description}
  • - Search by Address + ${i18n.search.address}
  • - Search by Place Name + ${i18n.search.place}
  • - Search By Zip Code, County, etc. + ${i18n.search.etc}
-
- In addition to Search capabilities, the following tools are provided: +
+ ${i18n.tools.description}
  • - Measure + ${i18n.tools.measure.title}
  • - The measure tool provides the capabilities to draw a point, line, or polygon - on the map and specify the unit of measurement. + ${i18n.tools.measure.description}
  • - Print + ${i18n.tools.print.title}
  • - This map can be exported to varouis formats and layouts + ${i18n.tools.print.description}
diff --git a/viewer/js/gis/dijit/Identify.js b/viewer/js/gis/dijit/Identify.js index 1a7775fd5..ccae23bc5 100644 --- a/viewer/js/gis/dijit/Identify.js +++ b/viewer/js/gis/dijit/Identify.js @@ -16,13 +16,18 @@ define([ 'esri/tasks/IdentifyTask', 'esri/tasks/IdentifyParameters', 'esri/dijit/PopupTemplate', + 'esri/layers/FeatureLayer', + 'esri/TimeExtent', + 'dojo/Deferred', 'dojo/text!./Identify/templates/Identify.html', 'dojo/i18n!./Identify/nls/resource', + './Identify/Formatters', 'dijit/form/Form', 'dijit/form/FilteringSelect', 'xstyle/css!./Identify/css/Identify.css' -], function (declare, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, MenuItem, lang, array, all, topic, query, domStyle, domClass, Moveable, Memory, IdentifyTask, IdentifyParameters, PopupTemplate, IdentifyTemplate, i18n) { +], function (declare, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, MenuItem, lang, array, all, topic, query, domStyle, domClass, Moveable, Memory, IdentifyTask, IdentifyParameters, PopupTemplate, FeatureLayer, TimeExtent, Deferred, IdentifyTemplate, i18n, Formatters) { + return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], { widgetsInTemplate: true, templateString: IdentifyTemplate, @@ -32,11 +37,31 @@ define([ mapClickMode: null, identifies: {}, infoTemplates: {}, + featureLayers: {}, ignoreOtherGraphics: true, createDefaultInfoTemplates: true, draggable: false, layerSeparator: '||', allLayersId: '***', + excludedFields: [ + 'objectid', 'esri_oid', 'shape', + 'shape.len', 'shape_length', + 'shape_len', 'shape.stlength()', + 'shape.area', 'shape_area', 'shape.starea()' + ], + /** + * field type mappings to their default formatter functions + * overriding this object will globally replace the default + * formatter function for the field type + * @type {Object} + */ + defaultFormatters: { + 'esriFieldTypeSmallInteger': Formatters.formatInt, + 'esriFieldTypeInteger': Formatters.formatInt, + 'esriFieldTypeSingle': Formatters.formatFloat, + 'esriFieldTypeDouble': Formatters.formatFloat, + 'esriFieldTypeDate': Formatters.formatDate + }, postCreate: function () { this.inherited(arguments); @@ -44,56 +69,10 @@ define([ this.identifies = {}; } this.layers = []; - array.forEach(this.layerInfos, function (layerInfo) { - var lyrId = layerInfo.layer.id; - var layer = this.map.getLayer(lyrId); - if (layer) { - var url = layer.url; - - // handle feature layers - if (layer.declaredClass === 'esri.layers.FeatureLayer') { - - // If is a feature layer that does not support - // Identify (Feature Service), create an - // infoTemplate for the graphic features. Create - // it only if one does not already exist. - if (layer.capabilities && layer.capabilities.toLowerCase().indexOf('data') < 0) { - if (!layer.infoTemplate) { - var infoTemplate = this.getInfoTemplate(layer, layer.layerId); - if (infoTemplate) { - layer.setInfoTemplate(infoTemplate); - return; - } - } - } - - // If it is a feature Layer, we get the base url - // for the map service by removing the layerId. - var lastSL = url.lastIndexOf('/' + layer.layerId); - if (lastSL > 0) { - url = url.substring(0, lastSL); - } - } - - this.layers.push({ - ref: layer, - layerInfo: layerInfo, - identifyTask: new IdentifyTask(url) - }); - - // rebuild the layer selection list when any layer is hidden - // but only if we have a UI - if (this.parentWidget) { - layer.on('visibility-change', lang.hitch(this, function (evt) { - if (evt.visible === false) { - this.createIdentifyLayerList(); - } - })); - } - } - }, this); + this.addLayerInfos(this.layerInfos); this.own(topic.subscribe('mapClickMode/currentSet', lang.hitch(this, 'setMapClickMode'))); + this.own(topic.subscribe('identify/addLayerInfos', lang.hitch(this, 'addLayerInfos'))); this.map.on('click', lang.hitch(this, function (evt) { if (this.mapClickMode === 'identify') { @@ -117,6 +96,80 @@ define([ this.setupDraggable(); } }, + /** + * handles an array of layerInfos to call addLayerInfo for each layerInfo + * @param {Array} layerInfos The array of layer infos + * @returns {undefined} + */ + addLayerInfos: function (layerInfos) { + array.forEach(layerInfos, lang.hitch(this, 'addLayerInfo')); + }, + /** + * Initializes an infoTemplate on a layerInfo.layer object if it doesn't + * exist already. + * @param {object} layerInfo A cmv layerInfo object that contains a layer property + * @return {undefined} + */ + addLayerInfo: function (layerInfo) { + var lyrId = layerInfo.layer.id, layer = this.map.getLayer(lyrId), infoTemplate; + if (layer) { + var url = layer.url; + + // handle feature layers + if (layer.declaredClass === 'esri.layers.FeatureLayer') { + + // If is a feature layer that does not support + // Identify (Feature Service), create an + // infoTemplate for the graphic features. Create + // it only if one does not already exist. + if (layer.capabilities && array.indexOf(layer.capabilities.toLowerCase(), 'data') < 0) { + if (!layer.infoTemplate) { + infoTemplate = this.getInfoTemplate(layer, layer.layerId); + if (infoTemplate) { + layer.setInfoTemplate(infoTemplate); + var fieldInfos = infoTemplate.info.fieldInfos; + var formatters = array.filter(fieldInfos, function (info) { + return (info.formatter); + }); + if (formatters.length > 0) { + layer.on('graphic-draw', lang.hitch(this, 'getFormattedFeature', layer.infoTemplate)); + } + } + } + } + + // If it is a feature Layer, we get the base url + // for the map service by removing the layerId. + var lastSL = url.lastIndexOf('/' + layer.layerId); + if (lastSL > 0) { + url = url.substring(0, lastSL); + } + } else if (layer.layerInfos) { + array.forEach(layer.layerInfos, lang.hitch(this, function (subLayerInfo) { + var subLayerId = subLayerInfo.id; + if ((layerInfo.layerIds === null) || (array.indexOf(layerInfo.layerIds, subLayerId) >= 0)) { + this.getFeatureLayerForDynamicSublayer(layer, subLayerId); + } + })); + } + + this.layers.push({ + ref: layer, + layerInfo: layerInfo, + identifyTask: new IdentifyTask(url) + }); + + // rebuild the layer selection list when any layer is hidden + // but only if we have a UI + if (this.parentWidget) { + layer.on('visibility-change', lang.hitch(this, function (evt) { + if (evt.visible === false) { + this.createIdentifyLayerList(); + } + })); + } + } + }, addRightClickMenu: function () { this.map.on('MouseDown', lang.hitch(this, function (evt) { this.mapRightClick = evt; @@ -129,7 +182,7 @@ define([ setupDraggable: function () { var popups, handles, pointers, movable; // the popup, handle (title) and pointers (arrows) - popups = query('div.esriPopup'); + popups = query('div.esriPopup'); handles = query('div.esriPopup div.titlePane div.title'); pointers = query('div.esriPopup div.outerPointer, div.esriPopup div.pointer'); @@ -150,8 +203,27 @@ define([ } }, executeIdentifyTask: function (evt) { + + + var mapPoint = evt.mapPoint; + var identifyParams = this.createIdentifyParams(mapPoint); + var identifies = []; + var identifiedlayers = []; + var selectedLayer = this.getSelectedLayer(); + + if (!this.checkForGraphicInfoTemplate(evt)) { - return; + // return; + var layer = array.filter(this.layers, function (l) { + return l.ref.id === evt.graphic._layer.id; + })[0]; + if (!layer) { + return; + } + identifiedlayers.push(layer); + var d = new Deferred(); + identifies.push(d.promise); + d.resolve([{feature: evt.graphic}]); } this.map.infoWindow.hide(); @@ -162,25 +234,23 @@ define([ return; } - var mapPoint = evt.mapPoint; - var identifyParams = this.createIdentifyParams(mapPoint); - var identifies = []; - var identifiedlayers = []; - var selectedLayer = this.getSelectedLayer(); - array.forEach(this.layers, lang.hitch(this, function (layer) { - var layerIds = this.getLayerIds(layer, selectedLayer); + array.forEach(this.layers, lang.hitch(this, function (lyr) { + var layerIds = this.getLayerIds(lyr, selectedLayer); if (layerIds.length > 0) { var params = lang.clone(identifyParams); - params.layerDefinitions = layer.ref.layerDefinitions; + params.layerDefinitions = lyr.ref.layerDefinitions; params.layerIds = layerIds; - identifies.push(layer.identifyTask.execute(params)); - identifiedlayers.push(layer); + if (lyr.ref.timeInfo && lyr.ref.timeInfo.timeExtent && this.map.timeExtent) { + params.timeExtent = new TimeExtent(this.map.timeExtent.startTime, this.map.timeExtent.endTime); + } + identifies.push(lyr.identifyTask.execute(params)); + identifiedlayers.push(lyr); } })); if (identifies.length > 0) { - this.map.infoWindow.setTitle( this.i18n.mapInfoWindow.identifyingTitle ); + this.map.infoWindow.setTitle(this.i18n.mapInfoWindow.identifyingTitle); this.map.infoWindow.setContent('
'); this.map.infoWindow.show(mapPoint); all(identifies).then(lang.hitch(this, 'identifyCallback', identifiedlayers), lang.hitch(this, 'identifyError')); @@ -192,7 +262,7 @@ define([ // handle feature layers that come from a feature service // and may already have an info template var layer = evt.graphic._layer; - if (layer.infoTemplate || (layer.capabilities && layer.capabilities.toLowerCase().indexOf('data') < 0)) { + if (layer.infoTemplate || (layer.capabilities && array.indexOf(layer.capabilities.toLowerCase(), 'data') < 0)) { return false; } @@ -254,7 +324,7 @@ define([ } else if ((ref.declaredClass === 'esri.layers.FeatureLayer') && !isNaN(ref.layerId)) { // feature layer // do not allow feature layer that does not support // Identify (Feature Service) - if (ref.capabilities && ref.capabilities.toLowerCase().indexOf('data') > 0) { + if (ref.capabilities && array.indexOf(ref.capabilities.toLowerCase(), 'data') >= 0) { layerIds = [ref.layerId]; } } else if (ref.layerInfos) { @@ -286,16 +356,33 @@ define([ if (result.feature.infoTemplate === undefined) { var infoTemplate = this.getInfoTemplate(ref, null, result); if (infoTemplate) { + if (result.layerId && ref.layerInfos && infoTemplate.info.showAttachments) { + result.feature._layer = this.getFeatureLayerForDynamicSublayer(ref, result.layerId); + } result.feature.setInfoTemplate(infoTemplate); } else { return; } } - fSet.push(result.feature); + var feature = this.getFormattedFeature(result.feature.infoTemplate, result.feature); + fSet.push(feature); }, this); }, this); this.map.infoWindow.setFeatures(fSet); }, + getFormattedFeature: function (infoTemplate, feature) { + if (feature.graphic) { + feature = feature.graphic; + } + if (feature && infoTemplate && infoTemplate.info) { + array.forEach(infoTemplate.info.fieldInfos, function (info) { + if (typeof info.formatter === 'function') { + feature.attributes[info.fieldName] = info.formatter(feature.attributes[info.fieldName], feature.attributes, lang.clone(feature.geometry)); + } + }); + } + return feature; + }, identifyError: function (err) { this.map.infoWindow.hide(); topic.publish('viewer/handleError', { @@ -308,43 +395,41 @@ define([ }, getInfoTemplate: function (layer, layerId, result) { - var popup = null, - content = null; + var popup, config; if (result) { - layerId = result.layerId; + layerId = result.layerId || layer.layerId; } else if (layerId === null) { layerId = layer.layerId; } - // see if we have a Popup config defined for this layer - if (this.identifies.hasOwnProperty(layer.id)) { - if (this.identifies[layer.id].hasOwnProperty(layerId)) { - popup = this.identifies[layer.id][layerId]; - if (popup) { - if (typeof (popup.declaredClass) !== 'string') { // has it been created already? - if (popup.content) { - content = popup.content; - } - popup = new PopupTemplate(popup); - if (content) { - popup.setContent(content); - } - this.identifies[layer.id][layerId] = popup; - } + var ids = this.identifies; + if (ids.hasOwnProperty(layer.id)) { + if (ids[layer.id].hasOwnProperty(layerId)) { + popup = ids[layer.id][layerId]; + if (popup instanceof PopupTemplate) { + return popup; } } + } else { + ids[layer.id] = {}; } - // if no Popup config found, create one with all attributes or layer fields - if (!popup) { - popup = this.createInfoTemplate(layer, layerId, result); + // by mixin in the users config with the default props we can + // generate a config object that provides the basics automatically + // while letting the user override only the parts they want...like mediaInfos + config = lang.mixin(this.createDefaultInfoTemplate(layer, layerId, result), ids[layer.id][layerId] || {}); + + popup = ids[layer.id][layerId] = new PopupTemplate(config); + if (config.content) { + popup.setContent(config.content); } - return popup; + return ids[layer.id][layerId]; }, - createInfoTemplate: function (layer, layerId, result) { - var popup = null, fieldInfos = []; + createDefaultInfoTemplate: function (layer, layerId, result) { + var popup = null, + fieldInfos = []; var layerName = this.getLayerName(layer); if (result) { @@ -357,57 +442,77 @@ define([ if (attributes) { for (var prop in attributes) { if (attributes.hasOwnProperty(prop)) { - fieldInfos.push({ + this.addDefaultFieldInfo(fieldInfos, { fieldName: prop, + label: this.makeSentenceCase(prop), visible: true }); } } } - // from the outFields of the layer + // from the outFields of the layer } else if (layer._outFields && (layer._outFields.length) && (layer._outFields[0] !== '*')) { var fields = layer.fields; - array.forEach(layer._outFields, function (fieldName) { + array.forEach(layer._outFields, lang.hitch(this, function (fieldName) { var foundField = array.filter(fields, function (field) { return (field.name === fieldName); }); if (foundField.length > 0) { - fieldInfos.push({ + this.addDefaultFieldInfo(fieldInfos, { fieldName: foundField[0].name, label: foundField[0].alias, visible: true }); } - }); + })); - // from the fields layer + // from the fields layer } else if (layer.fields) { - array.forEach(layer.fields, function (field) { - fieldInfos.push({ + array.forEach(layer.fields, lang.hitch(this, function (field) { + this.addDefaultFieldInfo(fieldInfos, { fieldName: field.name, - label: field.alias, + label: field.alias === field.name ? this.makeSentenceCase(field.name) : field.alias, visible: true }); - }); + })); } if (fieldInfos.length > 0) { - popup = new PopupTemplate({ + popup = { title: layerName, fieldInfos: fieldInfos, showAttachments: (layer.hasAttachments) - }); - if (!this.identifies[layer.id]) { - this.identifies[layer.id] = {}; - } - this.identifies[layer.id][layerId] = popup; + }; } return popup; }, + /** + * converts a string to a nice sentence case format + * @url http://stackoverflow.com/questions/196972/convert-string-to-title-case-with-javascript + * @param {string} str The string to convert + * @return {string} The converted string + */ + makeSentenceCase: function (str) { + if (!str.length) { + return ''; + } + str = str.toLowerCase().replace(/_/g, ' ').split(' '); + for (var i = 0; i < str.length; i++) { + str[i] = str[i].charAt(0).toUpperCase() + (str[i].substr(1).length ? str[i].substr(1) : ''); + } + return (str.length ? str.join(' ') : str); + }, + + addDefaultFieldInfo: function (fieldInfos, field) { + var nameLC = field.fieldName.toLowerCase(); + if (array.indexOf(this.excludedFields, nameLC) < 0) { + fieldInfos.push(field); + } + }, createIdentifyLayerList: function () { var id = null; @@ -474,8 +579,10 @@ define([ if (layerInfo.subLayerIds !== null) { return false; } - // only include sublayers that are currently visible - if (array.indexOf(ref.visibleLayers, layerInfo.id) < 0) { + + if (this.isDefaultLayerVisibility(ref) && !this.checkVisibilityRecursive(ref, layerInfo.id)) { + return false; + } else if (array.indexOf(ref.visibleLayers, layerInfo.id) < 0) { return false; } // only include sublayers that are within the current map scale @@ -503,6 +610,44 @@ define([ return true; }, + /** + * recursively check all a layer's parent(s) layers for visibility + * this only needs to be done if the layers visibleLayers array is + * set to the default visibleLayers. After setVisibleLayers + * is called the first time group layers are NOT included. + * @param {esri/layers/DynamicMapServiceLayer} layer The layer reference + * @param {Integer} id The sublayer id to check for visibility + * @return {Boolean} Whether or not the sublayer is visible based on its parent(s) visibility + */ + checkVisibilityRecursive: function (layer, id) { + var layerInfos = array.filter(layer.layerInfos, function (layerInfo) { + return (layerInfo.id === id); + }); + if (layerInfos.length > 0) { + var info = layerInfos[0]; + if (layer.visibleLayers.indexOf(id) !== -1 && + (info.parentLayerId === -1 || this.checkVisibilityRecursive(layer, info.parentLayerId))) { + return true; + } + } + return false; + }, + /** + * check each defaultVisibility and if its not in the visibleLayers + * array, then the layer has non-default layer visibility + * @param {esri/layers/DynamicMapServiceLayer} layer The layer reference + * @return {Boolean} Whether or not we're operating with the default visibleLayers array or not + */ + isDefaultLayerVisibility: function (layer) { + for (var i = 0; i < layer.layerInfos.length; i++) { + var item = layer.layerInfos[i]; + if (item.defaultVisibility && layer.visibleLayers.indexOf(item.id) === -1) { + return false; + } + } + return true; + }, + getLayerName: function (layer) { var name = null; if (layer.layerInfo) { @@ -525,6 +670,17 @@ define([ return name; }, + getFeatureLayerForDynamicSublayer: function (layer, layerId) { + if (!layer.layerInfos) { + return false; + } + var key = layer.url + '/' + layerId; + if (!this.featureLayers.hasOwnProperty(key)) { + this.featureLayers[key] = new FeatureLayer(key); + } + return this.featureLayers[key]; + }, + layerVisibleAtCurrentScale: function (layer) { var mapScale = this.map.getScale(); return !(((layer.maxScale !== 0 && mapScale < layer.maxScale) || (layer.minScale !== 0 && mapScale > layer.minScale))); @@ -544,14 +700,12 @@ define([ } // remove any infoTemplates that might // interfere with clicking on a feature - } else { - if (layer.infoTemplate) { - this.infoTemplates[layer.id] = lang.clone(layer.infoTemplate); - layer.infoTemplate = null; - } + } else if (layer.infoTemplate) { + this.infoTemplates[layer.id] = lang.clone(layer.infoTemplate); + layer.infoTemplate = null; } } }, this); } }); -}); \ No newline at end of file +}); diff --git a/viewer/js/gis/dijit/Identify/Formatters.js b/viewer/js/gis/dijit/Identify/Formatters.js new file mode 100644 index 000000000..b7c259e9d --- /dev/null +++ b/viewer/js/gis/dijit/Identify/Formatters.js @@ -0,0 +1,21 @@ +define([ + 'dojo/number', + 'dojo/date/locale' +], function (number, locale) { + return { + formatInt: function (value) { + return number.format(value); + }, + formatFloat: function (value) { + return number.format(value, { + places: 3 + }); + }, + formatDate: function (value) { + var date = new Date(value); + return locale.format(date, { + formatLength: 'short' + }); + } + }; +}); diff --git a/viewer/js/gis/dijit/Identify/nls/es/resource.js b/viewer/js/gis/dijit/Identify/nls/es/resource.js new file mode 100644 index 000000000..fda941704 --- /dev/null +++ b/viewer/js/gis/dijit/Identify/nls/es/resource.js @@ -0,0 +1,12 @@ +define ({ + labels: { + selectLayer: 'Seleccione la opción "Todas las capas visibles" o una sola capa para identificar:', + allVisibleLayers: '*** Todas las capas visibles ***' + }, + rightClickMenuItem: { + label: 'Identificar aquí' + }, + mapInfoWindow: { + identifyingTitle: 'Identificando...' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Identify/nls/fr/resource.js b/viewer/js/gis/dijit/Identify/nls/fr/resource.js new file mode 100644 index 000000000..013c39962 --- /dev/null +++ b/viewer/js/gis/dijit/Identify/nls/fr/resource.js @@ -0,0 +1,12 @@ +define ({ + labels: { + selectLayer: 'Choisissez "Tous les calques visibles" ou une seule couche pour identifier:', + allVisibleLayers: '*** Tous les calques visibles ***' + }, + rightClickMenuItem: { + label: 'Identifier ici' + }, + mapInfoWindow: { + identifyingTitle: 'Identification...' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Identify/nls/pt-br/resource.js b/viewer/js/gis/dijit/Identify/nls/pt-br/resource.js new file mode 100644 index 000000000..1a4d3327b --- /dev/null +++ b/viewer/js/gis/dijit/Identify/nls/pt-br/resource.js @@ -0,0 +1,12 @@ +define({ + labels: { + selectLayer: 'Escolha "Todas Camadas Visíveis" ou uma camada única para Identificar:', + allVisibleLayers: '*** Todas Camadas Visíveis ***' + }, + rightClickMenuItem: { + label: 'Identifique aqui' + }, + mapInfoWindow: { + identifyingTitle: 'Identificando...' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Identify/nls/pt-pt/resource.js b/viewer/js/gis/dijit/Identify/nls/pt-pt/resource.js new file mode 100644 index 000000000..ab2998ff7 --- /dev/null +++ b/viewer/js/gis/dijit/Identify/nls/pt-pt/resource.js @@ -0,0 +1,12 @@ +define({ + labels: { + selectLayer: 'Escolher "Todas as camadas visíveis" ou uma única camada para identificar:', + allVisibleLayers: '*** Todas as camadas visíveis ***' + }, + rightClickMenuItem: { + label: 'Identificar aqui' + }, + mapInfoWindow: { + identifyingTitle: 'A identificar...' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Identify/nls/resource.js b/viewer/js/gis/dijit/Identify/nls/resource.js index 54093328c..f46111906 100644 --- a/viewer/js/gis/dijit/Identify/nls/resource.js +++ b/viewer/js/gis/dijit/Identify/nls/resource.js @@ -10,5 +10,9 @@ define ({ mapInfoWindow: { identifyingTitle: 'Identifying...' } - } + }, + 'es': true, + 'fr': true, + 'pt-br': true, + 'pt-pt': true }); \ No newline at end of file diff --git a/viewer/js/gis/dijit/LayerControl.js b/viewer/js/gis/dijit/LayerControl.js index 7d76297f0..4a8f14098 100644 --- a/viewer/js/gis/dijit/LayerControl.js +++ b/viewer/js/gis/dijit/LayerControl.js @@ -28,12 +28,13 @@ define([ esriConfig, require ) { + var LayerControl = declare([WidgetBase, Container], { map: null, layerInfos: [], icons: { - expand: 'fa-plus-square-o', - collapse: 'fa-minus-square-o', + expand: 'fa-caret-right', + collapse: 'fa-caret-down', checked: 'fa-check-square-o', unchecked: 'fa-square-o', update: 'fa-refresh', @@ -50,6 +51,7 @@ define([ noLegend: null, noZoom: null, noTransparency: null, + menu: {}, subLayerMenu: {}, swipe: null, swiperButtonStyle: 'position:absolute;top:20px;left:120px;z-index:50;', @@ -67,7 +69,9 @@ define([ csv: './LayerControl/controls/CSV', georss: './LayerControl/controls/GeoRSS', wms: './LayerControl/controls/WMS', + wfs: './LayerControl/controls/WFS', kml: './LayerControl/controls/KML', + vectortile: './LayerControl/controls/VectorTile', webtiled: './LayerControl/controls/WebTiled', imagevector: './LayerControl/controls/ImageVector', raster: './LayerControl/controls/Raster', @@ -82,6 +86,8 @@ define([ }); return; } + // add any user-defined controls - possibly for user-defined layers + this._controls = lang.mixin(this._controls, options.controls || {}); }, postCreate: function () { this.inherited(arguments); @@ -115,10 +121,22 @@ define([ this.overlayReorder = false; this.vectorReorder = false; } + this._addLayerControls(this.layerInfos); + this._subscribeToTopics(); + }, + _subscribeToTopics: function () { + this._removeLayerControlsHandler = topic.subscribe('layerControl/removeLayerControls', lang.hitch(this, function (layers) { + this._removeLayerControls(layers); + })); + this._addLayerControlsHandler = topic.subscribe('layerControl/addLayerControls', lang.hitch(this, function (layerInfos) { + this._addLayerControls(layerInfos); + })); + }, + _addLayerControls: function (layerInfos) { // load only the modules we need var modules = []; // push layer control mods - array.forEach(this.layerInfos, function (layerInfo) { + array.forEach(layerInfos, function (layerInfo) { // check if control is excluded var controlOptions = layerInfo.controlOptions; if (controlOptions && controlOptions.exclude === true) { @@ -136,7 +154,7 @@ define([ }, this); // load and go require(modules, lang.hitch(this, function () { - array.forEach(this.layerInfos, function (layerInfo) { + array.forEach(layerInfos, function (layerInfo) { // exclude from widget var controlOptions = layerInfo.controlOptions; if (controlOptions && controlOptions.exclude === true) { @@ -150,11 +168,51 @@ define([ this._checkReorder(); })); }, + // remove the control given an array of layers + _removeLayerControls: function (layers) { + // helper function to determine which children's layer have a match in the layers parameter + function _filterList (entry) { + return layers.reduce(function (prior, curr) { + return (curr === entry.layer) || prior; + }, false); + } + // get a list of ALL the layers that meet the criteria + var layerControlList = this._overlayContainer.getChildren().filter(function (c) { + return _filterList(c); + }).concat( + this._vectorContainer.getChildren().filter(function (c) { + return _filterList(c); + })).concat( + this.getChildren().filter(function (c) { + return _filterList(c); + })); + // follow the same logic as when the layers were added + array.forEach(layerControlList, lang.hitch(this, function (layerControl) { + if (this.separated) { + if (layerControl._layerType === 'overlay') { + this._overlayContainer.removeChild(layerControl); + } else { + this._vectorContainer.removeChild(layerControl); + } + } else { + this.removeChild(layerControl); + } + layerControl.destroy(); + })); + }, // create layer control and add to appropriate _container - _addControl: function (layerInfo, LayerControl) { - var layerControl = new LayerControl({ + _addControl: function (layerInfo, Control) { + var layer = (typeof layerInfo.layer === 'string') ? this.map.getLayer(layerInfo.layer) : layerInfo.layer; + if (layerInfo.controlOptions && (layerInfo.type === 'dynamic' || layerInfo.type === 'feature')) { + if (layer.loaded) { + this._applyLayerControlOptions(layerInfo.controlOptions, layer); + } else { + layer.on('load', lang.hitch(this, '_applyLayerControlOptions', layerInfo.controlOptions)); + } + } + var layerControl = new Control({ controller: this, - layer: (typeof layerInfo.layer === 'string') ? this.map.getLayer(layerInfo.layer) : layerInfo.layer, // check if we have a layer or just a layer id + layer: layer, layerTitle: layerInfo.title, controlOptions: lang.mixin({ noLegend: null, @@ -163,18 +221,84 @@ define([ swipe: null, expanded: false, sublayers: true, - menu: this.subLayerMenu[layerInfo.type] + menu: this.menu[layerInfo.type], + subLayerMenu: this.subLayerMenu[layerInfo.type] }, layerInfo.controlOptions) }); layerControl.startup(); + var position = layerInfo.position || 0; if (this.separated) { if (layerControl._layerType === 'overlay') { - this._overlayContainer.addChild(layerControl, 'first'); + this._overlayContainer.addChild(layerControl, position); } else { - this._vectorContainer.addChild(layerControl, 'first'); + this._vectorContainer.addChild(layerControl, position); } } else { - this.addChild(layerControl, 'first'); + this.addChild(layerControl, position); + } + }, + _applyLayerControlOptions: function (controlOptions, layer) { + if (typeof controlOptions.includeUnspecifiedLayers === 'undefined' && typeof controlOptions.subLayerInfos === 'undefined' && typeof controlOptions.excludedLayers === 'undefined') { + return; + } + var esriLayerInfos = []; + // Case 1: only show the layers that are explicitly listed + if (!controlOptions.includeUnspecifiedLayers && controlOptions.subLayerInfos && controlOptions.subLayerInfos.length !== 0) { + var subLayerInfos = array.map(controlOptions.subLayerInfos, function (sli) { + return sli.id; + }); + array.forEach(layer.layerInfos, function (li) { + if (array.indexOf(subLayerInfos, li.id) !== -1) { + esriLayerInfos.push(li); + } + }); + // Case 2: show ALL layers except those in the excluded list + } else if (controlOptions.excludedLayers) { + array.forEach(layer.layerInfos, function (li) { + if (array.indexOf(controlOptions.excludedLayers, li.id) === -1) { + esriLayerInfos.push(li); + } + }); + // Case 3: just override the values found in the subLayerInfos + } else if (controlOptions.subLayerInfos) { + // show ALL layers that are in the map service's layerInfos, but take care to override the properties of each subLayerInfo as configured + this._mixinLayerInfos(layer.layerInfos, controlOptions.subLayerInfos); + this._setSublayerVisibilities(layer); + return; + } + // Finally, if we made use of the esriLayerInfos, make sure to apply all the subLayerInfos that were defined to our new array of esri layer infos + if (controlOptions.subLayerInfos) { + this._mixinLayerInfos(esriLayerInfos, controlOptions.subLayerInfos); + } + layer.layerInfos = esriLayerInfos; + this._setSublayerVisibilities(layer); + }, + _setSublayerVisibilities: function (layer) { + var visibleIds = array.map(array.filter(layer.layerInfos, function (li) { + return li.defaultVisibility; + }), function (l) { + return l.id; + }); + layer.setVisibleLayers(visibleIds); + }, + _mixinLayerInfos: function (esriLayerInfos, subLayerInfos) { + // for each of the sublayers, go through the subLayerInfos from the controlOptions and see if defaultVisiblity is set to true or false + // then set each of the layer.layerInfos defaultVisibility appropriately + // assume defaultVisibility is true if it's not defined + if (subLayerInfos && subLayerInfos.length !== 0) { + array.forEach(subLayerInfos, function (sli) { + if (typeof sli.defaultVisibility === 'undefined') { + sli.defaultVisibility = true; + } + }); + array.forEach(esriLayerInfos, function (li) { + var sli = array.filter(subLayerInfos, function (s) { + return s.id === li.id; + }).shift(); + if (sli) { + lang.mixin(li, sli); + } + }); } }, // move control up in controller and layer up in map @@ -224,29 +348,37 @@ define([ if (this.separated) { if (this.vectorReorder) { array.forEach(this._vectorContainer.getChildren(), function (child) { - if (!child.getPreviousSibling()) { - child._reorderUp.set('disabled', true); - } else { - child._reorderUp.set('disabled', false); + if (child._reorderUp) { + if (!child.getPreviousSibling()) { + child._reorderUp.set('disabled', true); + } else { + child._reorderUp.set('disabled', false); + } } - if (!child.getNextSibling()) { - child._reorderDown.set('disabled', true); - } else { - child._reorderDown.set('disabled', false); + if (child._reorderDown) { + if (!child.getNextSibling()) { + child._reorderDown.set('disabled', true); + } else { + child._reorderDown.set('disabled', false); + } } }, this); } if (this.overlayReorder) { array.forEach(this._overlayContainer.getChildren(), function (child) { - if (!child.getPreviousSibling()) { - child._reorderUp.set('disabled', true); - } else { - child._reorderUp.set('disabled', false); + if (child._reorderUp) { + if (!child.getPreviousSibling()) { + child._reorderUp.set('disabled', true); + } else { + child._reorderUp.set('disabled', false); + } } - if (!child.getNextSibling()) { - child._reorderDown.set('disabled', true); - } else { - child._reorderDown.set('disabled', false); + if (child._reorderDown) { + if (!child.getNextSibling()) { + child._reorderDown.set('disabled', true); + } else { + child._reorderDown.set('disabled', false); + } } }, this); } @@ -263,25 +395,23 @@ define([ var map = this.map; if (layer.spatialReference === map.spatialReference) { map.setExtent(layer.fullExtent, true); - } else { - if (esriConfig.defaults.geometryService) { - esriConfig.defaults.geometryService.project(lang.mixin(new ProjectParameters(), { - geometries: [layer.fullExtent], - outSR: map.spatialReference - }), function (r) { - map.setExtent(r[0], true); - }, function (e) { - topic.publish('viewer/handleError', { - source: 'LayerControl._zoomToLayer', - error: e - }); - }); - } else { + } else if (esriConfig.defaults.geometryService) { + esriConfig.defaults.geometryService.project(lang.mixin(new ProjectParameters(), { + geometries: [layer.fullExtent], + outSR: map.spatialReference + }), function (r) { + map.setExtent(r[0], true); + }, function (e) { topic.publish('viewer/handleError', { source: 'LayerControl._zoomToLayer', - error: 'esriConfig.defaults.geometryService is not set' + error: e }); - } + }); + } else { + topic.publish('viewer/handleError', { + source: 'LayerControl._zoomToLayer', + error: 'esriConfig.defaults.geometryService is not set' + }); } }, // layer swiper @@ -359,4 +489,4 @@ define([ } }); return LayerControl; -}); \ No newline at end of file +}); diff --git a/viewer/js/gis/dijit/LayerControl/controls/CSV.js b/viewer/js/gis/dijit/LayerControl/controls/CSV.js index d5efc3784..e34b5db92 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/CSV.js +++ b/viewer/js/gis/dijit/LayerControl/controls/CSV.js @@ -13,6 +13,7 @@ define([ _Control, legendUtil ) { + var CSVControl = declare([_WidgetBase, _TemplatedMixin, _Contained, _Control], { _layerType: 'vector', // constant _esriLayerType: 'csv', // constant diff --git a/viewer/js/gis/dijit/LayerControl/controls/Dynamic.js b/viewer/js/gis/dijit/LayerControl/controls/Dynamic.js index caa52aa16..c4ce2a847 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/Dynamic.js +++ b/viewer/js/gis/dijit/LayerControl/controls/Dynamic.js @@ -39,6 +39,7 @@ define([ legendUtil, i18n ) { + var DynamicControl = declare([_WidgetBase, _TemplatedMixin, _Contained, _Control], { _layerType: 'overlay', // constant _esriLayerType: 'dynamic', // constant @@ -87,6 +88,13 @@ define([ menu.addChild(new MenuSeparator()); } }, + _initCustomMenu: function () { + // add custom sublayer menu items if we only have one sublayer + if (!this._hasSublayers) { + array.forEach(this.controlOptions.subLayerMenu, lang.hitch(this, '_addCustomMenuItem', this.layerMenu)); + this.layerMenu.addChild(new MenuSeparator()); + } + }, // toggle all sublayers on/off _toggleAllSublayers: function (state) { array.forEach(this._sublayerControls, function (control) { @@ -98,29 +106,40 @@ define([ _createSublayers: function (layer) { // check for single sublayer - if so no sublayer/folder controls if (layer.layerInfos.length > 1) { + var allLayers = array.map(layer.layerInfos, function (l) { + return l.id; + }); array.forEach(layer.layerInfos, lang.hitch(this, function (info) { + // see if there was any override needed from the subLayerInfos array in the controlOptions + var sublayerInfo = array.filter(this.controlOptions.subLayerInfos, function (sli) { + return sli.id === info.id; + }).shift(); + lang.mixin(info, sublayerInfo); var pid = info.parentLayerId, slids = info.subLayerIds, controlId = layer.id + '-' + info.id + '-sublayer-control', control; - if (pid === -1 && slids === null) { - // it's a top level sublayer - control = new DynamicSublayer({ - id: controlId, - control: this, - sublayerInfo: info, - icons: this.icons - }); - domConst.place(control.domNode, this.expandNode, 'last'); - } else if (pid === -1 && slids !== null) { - // it's a top level folder - control = new DynamicFolder({ - id: controlId, - control: this, - sublayerInfo: info, - icons: this.icons - }); - domConst.place(control.domNode, this.expandNode, 'last'); + // it's a top level + if (pid === -1 || allLayers.indexOf(pid) === -1) { + if (slids === null) { + // it's a top level sublayer + control = new DynamicSublayer({ + id: controlId, + control: this, + sublayerInfo: info, + icons: this.icons + }); + domConst.place(control.domNode, this.expandNode, 'last'); + } else if (slids !== null) { + // it's a top level folder + control = new DynamicFolder({ + id: controlId, + control: this, + sublayerInfo: info, + icons: this.icons + }); + domConst.place(control.domNode, this.expandNode, 'last'); + } } else if (pid !== -1 && slids !== null) { // it's a nested folder control = new DynamicFolder({ @@ -210,4 +229,4 @@ define([ } }); return DynamicControl; -}); \ No newline at end of file +}); diff --git a/viewer/js/gis/dijit/LayerControl/controls/Feature.js b/viewer/js/gis/dijit/LayerControl/controls/Feature.js index 2da71fec8..8706f5e29 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/Feature.js +++ b/viewer/js/gis/dijit/LayerControl/controls/Feature.js @@ -13,6 +13,7 @@ define([ _Control, legendUtil ) { + var FeatureControl = declare([_WidgetBase, _TemplatedMixin, _Contained, _Control], { _layerType: 'vector', // constant _esriLayerType: 'feature', // constant @@ -27,4 +28,4 @@ define([ } }); return FeatureControl; -}); \ No newline at end of file +}); diff --git a/viewer/js/gis/dijit/LayerControl/controls/GeoRSS.js b/viewer/js/gis/dijit/LayerControl/controls/GeoRSS.js index c149b7411..86e99a560 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/GeoRSS.js +++ b/viewer/js/gis/dijit/LayerControl/controls/GeoRSS.js @@ -11,6 +11,7 @@ define([ _Contained, _Control ) { + var GeoRSSControl = declare([_WidgetBase, _TemplatedMixin, _Contained, _Control], { _layerType: 'vector', // constant _esriLayerType: 'georss', // constant diff --git a/viewer/js/gis/dijit/LayerControl/controls/Image.js b/viewer/js/gis/dijit/LayerControl/controls/Image.js index 6d0f1c597..6b845d01c 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/Image.js +++ b/viewer/js/gis/dijit/LayerControl/controls/Image.js @@ -13,6 +13,7 @@ define([ _Control, legendUtil ) { + var ImageControl = declare([_WidgetBase, _TemplatedMixin, _Contained, _Control], { _layerType: 'overlay', // constant _esriLayerType: 'image', // constant diff --git a/viewer/js/gis/dijit/LayerControl/controls/ImageVector.js b/viewer/js/gis/dijit/LayerControl/controls/ImageVector.js index add67e581..512b19ac4 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/ImageVector.js +++ b/viewer/js/gis/dijit/LayerControl/controls/ImageVector.js @@ -13,6 +13,7 @@ define([ _Control, legendUtil ) { + var ImageVectorControl = declare([_WidgetBase, _TemplatedMixin, _Contained, _Control], { _layerType: 'overlay', // constant _esriLayerType: 'imagevector', // constant diff --git a/viewer/js/gis/dijit/LayerControl/controls/KML.js b/viewer/js/gis/dijit/LayerControl/controls/KML.js index 21a32944d..5042c8df2 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/KML.js +++ b/viewer/js/gis/dijit/LayerControl/controls/KML.js @@ -13,6 +13,7 @@ define([ _Control, legendUtil ) { + var KMLControl = declare([_WidgetBase, _TemplatedMixin, _Contained, _Control], { _layerType: 'vector', // constant _esriLayerType: 'kml', // constant diff --git a/viewer/js/gis/dijit/LayerControl/controls/Raster.js b/viewer/js/gis/dijit/LayerControl/controls/Raster.js index c31195189..1ab1bf896 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/Raster.js +++ b/viewer/js/gis/dijit/LayerControl/controls/Raster.js @@ -11,6 +11,7 @@ define([ _Contained, _Control ) { + var RasterControl = declare([_WidgetBase, _TemplatedMixin, _Contained, _Control], { _layerType: 'overlay', // constant _esriLayerType: 'raster', // constant diff --git a/viewer/js/gis/dijit/LayerControl/controls/Stream.js b/viewer/js/gis/dijit/LayerControl/controls/Stream.js index 3f711d3d2..385cae7a8 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/Stream.js +++ b/viewer/js/gis/dijit/LayerControl/controls/Stream.js @@ -13,6 +13,7 @@ define([ _Control, legendUtil ) { + var StreamControl = declare([_WidgetBase, _TemplatedMixin, _Contained, _Control], { _layerType: 'overlay', // constant _esriLayerType: 'raster', // constant diff --git a/viewer/js/gis/dijit/LayerControl/controls/Tiled.js b/viewer/js/gis/dijit/LayerControl/controls/Tiled.js index 4e57b229b..242fe3acb 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/Tiled.js +++ b/viewer/js/gis/dijit/LayerControl/controls/Tiled.js @@ -13,6 +13,7 @@ define([ _Control, legendUtil ) { + var TiledControl = declare([_WidgetBase, _TemplatedMixin, _Contained, _Control], { _layerType: 'overlay', // constant _esriLayerType: 'tiled', // constant diff --git a/viewer/js/gis/dijit/LayerControl/controls/VectorTile.js b/viewer/js/gis/dijit/LayerControl/controls/VectorTile.js new file mode 100644 index 000000000..f6901ad4a --- /dev/null +++ b/viewer/js/gis/dijit/LayerControl/controls/VectorTile.js @@ -0,0 +1,23 @@ +define([ + 'dojo/_base/declare', + 'dijit/_WidgetBase', + 'dijit/_TemplatedMixin', + 'dijit/_Contained', + './_Control' // layer control base class +], function ( + declare, + _WidgetBase, + _TemplatedMixin, + _Contained, + _Control +) { + + var VectorTileControl = declare([_WidgetBase, _TemplatedMixin, _Contained, _Control], { + _layerType: 'overlay', // constant + _esriLayerType: 'vectortile', // constant + _layerTypeInit: function () { + this._expandRemove(); + } + }); + return VectorTileControl; +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/LayerControl/controls/WFS.js b/viewer/js/gis/dijit/LayerControl/controls/WFS.js new file mode 100644 index 000000000..848e41d99 --- /dev/null +++ b/viewer/js/gis/dijit/LayerControl/controls/WFS.js @@ -0,0 +1,24 @@ +define([ + 'dojo/_base/declare', + 'dijit/_WidgetBase', + 'dijit/_TemplatedMixin', + 'dijit/_Contained', + './_Control', // layer control base class + './../plugins/legendUtil' +], function ( + declare, + _WidgetBase, + _TemplatedMixin, + _Contained, + _Control +) { + + var WFSControl = declare([_WidgetBase, _TemplatedMixin, _Contained, _Control], { + _layerType: 'vector', // constant + _esriLayerType: 'wfs', // constant + _layerTypeInit: function () { + this._expandRemove(); + } + }); + return WFSControl; +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/LayerControl/controls/WMS.js b/viewer/js/gis/dijit/LayerControl/controls/WMS.js index 443e13232..21817901b 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/WMS.js +++ b/viewer/js/gis/dijit/LayerControl/controls/WMS.js @@ -11,6 +11,7 @@ define([ _Contained, _Control ) { + var WMSControl = declare([_WidgetBase, _TemplatedMixin, _Contained, _Control], { _layerType: 'overlay', // constant _esriLayerType: 'wms', // constant diff --git a/viewer/js/gis/dijit/LayerControl/controls/WebTiled.js b/viewer/js/gis/dijit/LayerControl/controls/WebTiled.js index 7393cd952..3287bcbb8 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/WebTiled.js +++ b/viewer/js/gis/dijit/LayerControl/controls/WebTiled.js @@ -11,6 +11,7 @@ define([ _Contained, _Control ) { + var WebTiledControl = declare([_WidgetBase, _TemplatedMixin, _Contained, _Control], { _layerType: 'overlay', // constant _esriLayerType: 'webtiled', // constant diff --git a/viewer/js/gis/dijit/LayerControl/controls/_Control.js b/viewer/js/gis/dijit/LayerControl/controls/_Control.js index 4e39f478a..58e7f6179 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/_Control.js +++ b/viewer/js/gis/dijit/LayerControl/controls/_Control.js @@ -1,7 +1,7 @@ define([ 'dojo/_base/declare', 'dojo/_base/lang', - //'dojo/_base/array', + 'dojo/_base/array', 'dojo/on', 'dojo/topic', 'dojo/dom-construct', @@ -10,12 +10,13 @@ define([ 'dojo/dom-attr', 'dojo/fx', 'dojo/html', + 'dijit/MenuItem', './../plugins/LayerMenu', 'dojo/text!./templates/Control.html' ], function ( declare, lang, - //array, + array, on, topic, domConst, @@ -24,6 +25,7 @@ define([ domAttr, fx, html, + MenuItem, LayerMenu, template ) { @@ -43,6 +45,7 @@ define([ if (params.controller) { this.icons = params.controller.icons; } // if not you've got bigger problems + this._handlers = []; }, postCreate: function () { this.inherited(arguments); @@ -66,7 +69,7 @@ define([ if (this.layer.loaded) { this._initialize(); } else { - this.layer.on('load', lang.hitch(this, '_initialize')); + this._handlers.push(this.layer.on('load', lang.hitch(this, '_initialize'))); } }, // initialize the control @@ -79,17 +82,8 @@ define([ controlOptions = this.controlOptions; // set checkbox this._setLayerCheckbox(layer, this.checkNode); - // wire up layer visibility - on(this.checkNode, 'click', lang.hitch(this, '_setLayerVisibility', layer, this.checkNode)); // set title html.set(this.labelNode, this.layerTitle); - // wire up updating indicator - layer.on('update-start', lang.hitch(this, function () { - domStyle.set(this.layerUpdateNode, 'display', 'inline-block'); //font awesome display - })); - layer.on('update-end', lang.hitch(this, function () { - domStyle.set(this.layerUpdateNode, 'display', 'none'); - })); // create layer menu if ((controlOptions.noMenu !== true && this.controller.noMenu !== true) || (this.controller.noMenu === true && controlOptions.noMenu === false)) { this.layerMenu = new LayerMenu({ @@ -99,6 +93,7 @@ define([ leftClickToOpen: true }); this.layerMenu.startup(); + this._initCustomMenu(); } else { domClass.remove(this.menuNode, 'fa, layerControlMenuIcon, ' + this.icons.menu); domStyle.set(this.menuClickNode, 'cursor', 'default'); @@ -108,19 +103,6 @@ define([ this._checkboxScaleRange(); this._scaleRangeHandler = layer.getMap().on('zoom-end', lang.hitch(this, '_checkboxScaleRange')); } - // if layer scales change - this.layer.on('scale-range-change', lang.hitch(this, function () { - if (layer.minScale !== 0 || layer.maxScale !== 0) { - this._checkboxScaleRange(); - this._scaleRangeHandler = layer.getMap().on('zoom-end', lang.hitch(this, '_checkboxScaleRange')); - } else { - this._checkboxScaleRange(); - if (this._scaleRangeHandler) { - this._scaleRangeHandler.remove(); - this._scaleRangeHandler = null; - } - } - })); // a function in each control widget for layer type specifics like legends and such this._layerTypeInit(); // show expandNode @@ -130,30 +112,51 @@ define([ } // esri layer's don't inherit from Stateful // connect to update events to handle "watching" layers - layer.on('update-start', lang.hitch(this, '_updateStart')); - layer.on('update-end', lang.hitch(this, '_updateEnd')); - layer.on('visibility-change', lang.hitch(this, '_visibilityChange')); + this._handlers.push( + on(this.checkNode, 'click', lang.hitch(this, '_setLayerVisibility', layer, this.checkNode)), + layer.on('scale-range-change', lang.hitch(this, '_scaleRangeChange')), + layer.on('update-start', lang.hitch(this, '_updateStart')), + layer.on('update-end', lang.hitch(this, '_updateEnd')), + layer.on('visibility-change', lang.hitch(this, '_visibilityChange')) + ); + }, + _initCustomMenu: function () { + array.forEach(this.controlOptions.menu, lang.hitch(this, '_addCustomMenuItem', this.layerMenu)); + }, + _addCustomMenuItem: function (menu, menuItem) { + //create the menu item + var item = new MenuItem(menuItem); + item.set('onClick', lang.hitch(this, function () { + topic.publish('layerControl/' + menuItem.topic, { + layer: this.layer, + iconNode: this.iconNode, + menuItem: item + }); + })); + menu.addChild(item); }, // add on event to expandClickNode _expandClick: function () { - var i = this.icons; - this._expandClickHandler = on(this.expandClickNode, 'click', lang.hitch(this, function () { - var expandNode = this.expandNode, - iconNode = this.expandIconNode; - if (domStyle.get(expandNode, 'display') === 'none') { - fx.wipeIn({ - node: expandNode, - duration: 300 - }).play(); - domClass.replace(iconNode, i.collapse, i.expand); - } else { - fx.wipeOut({ - node: expandNode, - duration: 300 - }).play(); - domClass.replace(iconNode, i.expand, i.collapse); - } - })); + this._expandClickHandler = on(this.expandClickNode, 'click', lang.hitch(this, '_expandClicked')); + this._handlers.push(this._expandClickHandler); + }, + _expandClicked: function () { + var i = this.icons, + expandNode = this.expandNode, + iconNode = this.expandIconNode; + if (domStyle.get(expandNode, 'display') === 'none') { + fx.wipeIn({ + node: expandNode, + duration: 300 + }).play(); + domClass.replace(iconNode, i.collapse, i.expand); + } else { + fx.wipeOut({ + node: expandNode, + duration: 300 + }).play(); + domClass.replace(iconNode, i.expand, i.collapse); + } }, // removes the icons and cursor:pointer from expandClickNode and destroys expandNode _expandRemove: function () { @@ -162,7 +165,13 @@ define([ domConst.destroy(this.expandNode); }, // set layer visibility and update icon - _setLayerVisibility: function (layer, checkNode) { + _setLayerVisibility: function (layer, checkNode, event) { + + // prevent click event from bubbling + if (event.stopPropagation) { + event.stopPropagation(); + } + if (layer.visible) { this._setLayerCheckbox(layer, checkNode); layer.hide(); @@ -205,8 +214,33 @@ define([ domClass.add(node, 'layerControlCheckIconOutScale'); } }, + _scaleRangeChange: function () { + if (this.layer.minScale !== 0 || this.layer.maxScale !== 0) { + this._checkboxScaleRange(); + if (this._scaleRangeHandler) { + var handlerIndex = array.indexOf(this._handlers, this._scaleRangeHandler); + if (handlerIndex !== -1) { + this._handlers[handlerIndex].remove(); + this._handlers.splice(handlerIndex, 1); + } + } + this._scaleRangeHandler = this.layer.getMap().on('zoom-end', lang.hitch(this, '_checkboxScaleRange')); + this._handlers.push(this._scaleRangeHandler); + } else { + this._checkboxScaleRange(); + if (this._scaleRangeHandler) { + var handlerIndex2 = array.indexOf(this._handlers, this._scaleRangeHandler); + if (handlerIndex2 !== -1) { + this._handlers[handlerIndex2].remove(); + this._handlers.splice(handlerIndex2, 1); + } + this._scaleRangeHandler = null; + } + } + }, // anything the widget may need to do before update _updateStart: function () { + domStyle.set(this.layerUpdateNode, 'display', 'inline-block'); //font awesome display // clone a layer state before layer updates for use after update this._layerState = lang.clone({ visible: this.layer.visible, @@ -215,6 +249,7 @@ define([ }, // anything the widget may need to do after update _updateEnd: function () { + domStyle.set(this.layerUpdateNode, 'display', 'none'); // how to handle external layer.setVisibleLayers() ??? // // without topics to get/set sublayer state this will be challenging @@ -233,7 +268,13 @@ define([ if ((r.visible && domAttr.get(this.checkNode, 'data-checked') === 'unchecked') || (!r.visible && domAttr.get(this.checkNode, 'data-checked') === 'checked')) { this._setLayerCheckbox(this.layer, this.checkNode); } + }, + destroy: function () { + this.inherited(arguments); + this._handlers.forEach(function (h) { + h.remove(); + }); } }); return _Control; -}); \ No newline at end of file +}); diff --git a/viewer/js/gis/dijit/LayerControl/controls/_DynamicFolder.js b/viewer/js/gis/dijit/LayerControl/controls/_DynamicFolder.js index ffca235af..15a601720 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/_DynamicFolder.js +++ b/viewer/js/gis/dijit/LayerControl/controls/_DynamicFolder.js @@ -25,15 +25,29 @@ define([ TemplatedMixin, folderTemplate ) { - var _DynamicFolder = declare([WidgetBase, TemplatedMixin], { + var _DynamicFolder = declare([WidgetBase, TemplatedMixin], { control: null, sublayerInfo: null, icons: null, // ^args templateString: folderTemplate, _expandClickHandler: null, + _handlers: [], postCreate: function () { this.inherited(arguments); + // Should the control be visible or hidden (depends on subLayerInfos)? + if (this.control.controlOptions.subLayerInfos && !this.control.controlOptions.includeUnspecifiedLayers) { + var subLayerInfos = array.map(this.control.controlOptions.subLayerInfos, function (sli) { + return sli.id; + }); + if (array.indexOf(subLayerInfos, this.sublayerInfo.id) < 0) { + domClass.add(this.domNode, 'layerControlHidden'); + } + } + // Should the control be visible or hidden? + if (this.control.controlOptions.layerIds && array.indexOf(this.control.controlOptions.layerIds, this.sublayerInfo.id) < 0) { + domClass.add(this.domNode, 'layerControlHidden'); + } var checkNode = this.checkNode; domAttr.set(checkNode, 'data-sublayer-id', this.sublayerInfo.id); domClass.add(checkNode, this.control.layer.id + '-layerControlSublayerCheck'); @@ -42,7 +56,13 @@ define([ } else { this._setSublayerCheckbox(false, checkNode); } - on(checkNode, 'click', lang.hitch(this, function () { + this._handlers.push(on(checkNode, 'click', lang.hitch(this, function (event) { + + // prevent click event from bubbling + if (event.stopPropagation) { + event.stopPropagation(); + } + if (domAttr.get(checkNode, 'data-checked') === 'checked') { this._setSublayerCheckbox(false, checkNode); } else { @@ -50,18 +70,18 @@ define([ } this.control._setVisibleLayers(); this._checkboxScaleRange(); - })); + }))); html.set(this.labelNode, this.sublayerInfo.name); this._expandClick(); if (this.sublayerInfo.minScale !== 0 || this.sublayerInfo.maxScale !== 0) { this._checkboxScaleRange(); - this.control.layer.getMap().on('zoom-end', lang.hitch(this, '_checkboxScaleRange')); + this._handlers.push(this.control.layer.getMap().on('zoom-end', lang.hitch(this, '_checkboxScaleRange'))); } }, // add on event to expandClickNode _expandClick: function () { var i = this.icons; - this._expandClickHandler = on(this.expandClickNode, 'click', lang.hitch(this, function () { + this._handlers.push(this._expandClickHandler = on(this.expandClickNode, 'click', lang.hitch(this, function () { var expandNode = this.expandNode, iconNode = this.expandIconNode; if (domStyle.get(expandNode, 'display') === 'none') { @@ -77,7 +97,7 @@ define([ }).play(); domClass.replace(iconNode, i.folder, i.folderOpen); } - })); + }))); }, // set checkbox based on layer so it's always in sync _setSublayerCheckbox: function (checked, checkNode) { @@ -101,7 +121,13 @@ define([ if ((min !== 0 && scale > min) || (max !== 0 && scale < max)) { domClass.add(node, 'layerControlCheckIconOutScale'); } + }, + destroy: function () { + this.inherited(arguments); + this._handlers.forEach(function (h) { + h.remove(); + }); } }); return _DynamicFolder; -}); \ No newline at end of file +}); diff --git a/viewer/js/gis/dijit/LayerControl/controls/_DynamicSublayer.js b/viewer/js/gis/dijit/LayerControl/controls/_DynamicSublayer.js index 159427057..51c9dd271 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/_DynamicSublayer.js +++ b/viewer/js/gis/dijit/LayerControl/controls/_DynamicSublayer.js @@ -42,18 +42,37 @@ define([ templateString: sublayerTemplate, i18n: i18n, _expandClickHandler: null, + _handlers: [], postCreate: function () { this.inherited(arguments); + // Should the control be visible or hidden (depends on subLayerInfos)? + if (this.control.controlOptions.subLayerInfos && !this.control.controlOptions.includeUnspecifiedLayers) { + var subLayerInfos = array.map(this.control.controlOptions.subLayerInfos, function (sli) { + return sli.id; + }); + if (array.indexOf(subLayerInfos, this.sublayerInfo.id) < 0) { + domClass.add(this.domNode, 'layerControlHidden'); + } + } + // Should the control be visible or hidden? + if (this.control.controlOptions.layerIds && array.indexOf(this.control.controlOptions.layerIds, this.sublayerInfo.id) < 0) { + domClass.add(this.domNode, 'layerControlHidden'); + } var checkNode = this.checkNode; domAttr.set(checkNode, 'data-sublayer-id', this.sublayerInfo.id); domClass.add(checkNode, this.control.layer.id + '-layerControlSublayerCheck'); if (array.indexOf(this.control.layer.visibleLayers, this.sublayerInfo.id) !== -1) { this._setSublayerCheckbox(true, checkNode); } else { - this._setSublayerCheckbox(false, checkNode); } - on(checkNode, 'click', lang.hitch(this, function () { + this._handlers.push(on(checkNode, 'click', lang.hitch(this, function (event) { + + // prevent click event from bubbling + if (event.stopPropagation) { + event.stopPropagation(); + } + if (domAttr.get(checkNode, 'data-checked') === 'checked') { this._setSublayerCheckbox(false, checkNode); } else { @@ -61,38 +80,38 @@ define([ } this.control._setVisibleLayers(); this._checkboxScaleRange(); - })); + }))); html.set(this.labelNode, this.sublayerInfo.name); this._expandClick(); if (this.sublayerInfo.minScale !== 0 || this.sublayerInfo.maxScale !== 0) { this._checkboxScaleRange(); - this.control.layer.getMap().on('zoom-end', lang.hitch(this, '_checkboxScaleRange')); + this._handlers.push(this.control.layer.getMap().on('zoom-end', lang.hitch(this, '_checkboxScaleRange'))); } //set up menu - if (this.control.controlOptions.menu && - this.control.controlOptions.menu.length) { - domClass.add(this.labelNode, 'menuLink'); - domClass.add(this.iconNode, 'menuLink'); + if (this.control.controlOptions.subLayerMenu && + this.control.controlOptions.subLayerMenu.length) { this.menu = new Menu({ contextMenuForWindow: false, - targetNodeIds: [this.labelNode], + targetNodeIds: [this.menuClickNode], leftClickToOpen: true }); - array.forEach(this.control.controlOptions.menu, lang.hitch(this, '_addMenuItem')); + array.forEach(this.control.controlOptions.subLayerMenu, lang.hitch(this, '_addMenuItem')); this.menu.startup(); + } else { + domClass.add(this.menuClickNode, 'hidden'); } }, _addMenuItem: function (menuItem) { //create the menu item - var item = new MenuItem(menuItem); + var item = new MenuItem(menuItem); item.set('onClick', lang.hitch(this, function () { - topic.publish('LayerControl/' + menuItem.topic, { - layer: this.control.layer, - subLayer: this.sublayerInfo, - iconNode: this.iconNode, - menuItem: item - }); - })); + topic.publish('layerControl/' + menuItem.topic, { + layer: this.control.layer, + subLayer: this.sublayerInfo, + iconNode: this.iconNode, + menuItem: item + }); + })); this.menu.addChild(item); }, // add on event to expandClickNode @@ -100,7 +119,7 @@ define([ var i = this.icons; this._expandClickHandler = on(this.expandClickNode, 'click', lang.hitch(this, function () { var expandNode = this.expandNode, - iconNode = this.expandIconNode; + iconNode = this.expandIconNode; if (domStyle.get(expandNode, 'display') === 'none') { fx.wipeIn({ node: expandNode, @@ -115,6 +134,7 @@ define([ domClass.replace(iconNode, i.expand, i.collapse); } })); + this._handlers.push(this._expandClickHandler); }, // set checkbox based on layer so it's always in sync _setSublayerCheckbox: function (checked, checkNode) { @@ -131,14 +151,20 @@ define([ // check scales and add/remove disabled classes from checkbox _checkboxScaleRange: function () { var node = this.checkNode, - scale = this.control.layer.getMap().getScale(), - min = this.sublayerInfo.minScale, - max = this.sublayerInfo.maxScale; + scale = this.control.layer.getMap().getScale(), + min = this.sublayerInfo.minScale, + max = this.sublayerInfo.maxScale; domClass.remove(node, 'layerControlCheckIconOutScale'); if ((min !== 0 && scale > min) || (max !== 0 && scale < max)) { domClass.add(node, 'layerControlCheckIconOutScale'); } + }, + destroy: function () { + this.inherited(arguments); + this._handlers.forEach(function (h) { + h.remove(); + }); } }); return _DynamicSublayer; -}); \ No newline at end of file +}); diff --git a/viewer/js/gis/dijit/LayerControl/controls/templates/Control.html b/viewer/js/gis/dijit/LayerControl/controls/templates/Control.html index 5836fe4b0..e7e224030 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/templates/Control.html +++ b/viewer/js/gis/dijit/LayerControl/controls/templates/Control.html @@ -1,7 +1,7 @@
- - +
+
diff --git a/viewer/js/gis/dijit/LayerControl/controls/templates/Folder.html b/viewer/js/gis/dijit/LayerControl/controls/templates/Folder.html index 628438952..c62a97f34 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/templates/Folder.html +++ b/viewer/js/gis/dijit/LayerControl/controls/templates/Folder.html @@ -1,7 +1,7 @@ -
- - -
+
+ + +
diff --git a/viewer/js/gis/dijit/LayerControl/controls/templates/Sublayer.html b/viewer/js/gis/dijit/LayerControl/controls/templates/Sublayer.html index 8e5b82ea6..6d2a2b464 100644 --- a/viewer/js/gis/dijit/LayerControl/controls/templates/Sublayer.html +++ b/viewer/js/gis/dijit/LayerControl/controls/templates/Sublayer.html @@ -1,7 +1,7 @@ -
- - -
+
+ + + +
@@ -9,9 +9,14 @@ - + + + + +
- +
diff --git a/viewer/js/gis/dijit/LayerControl/css/LayerControl.css b/viewer/js/gis/dijit/LayerControl/css/LayerControl.css index f805803da..c3fa09b4e 100644 --- a/viewer/js/gis/dijit/LayerControl/css/LayerControl.css +++ b/viewer/js/gis/dijit/LayerControl/css/LayerControl.css @@ -45,8 +45,7 @@ line-height: 15px; } -.layerControlDijit .layerControlTableCheck, -.layerControlDijit .layerControlTableMenu { +.layerControlDijit .layerControlTableCheck, .layerControlDijit .layerControlTableMenu { cursor: pointer; width: 19px; height: 16px; @@ -54,10 +53,14 @@ } .layerControlDijit .layerControlTableLabel { + cursor: pointer; font-size: 15px; height: 16px; line-height: 16px; - cursor: default; +} + +.layerControlDijit .layerControlTableMenu { + cursor: pointer; } .layerControlDijit .layerControlTableUpdate { @@ -67,6 +70,14 @@ text-align: center; } +.layerControlDijit .layerControlHidden { + display: none; +} + +.layerControlDijit .layerControlVisible { + display: block; +} + .layerControlDijit .layerControlIndent { padding-left: 22px; } @@ -92,7 +103,9 @@ color: #BBB; } + /* not in use - retain for links */ + .layerControlDijit .layerControlClick { cursor: pointer; color: #1f78af; @@ -111,7 +124,7 @@ vertical-align: middle; } -.layerControlDijit .layerControlLegendImage > img { +.layerControlDijit .layerControlLegendImage>img { border: none; padding: 0; } @@ -120,7 +133,9 @@ padding: 0 0 0 4px; } + /* temp esri/Legend overrides */ + .layerControlDijit .esriLegendService td { padding: 0; } @@ -133,13 +148,12 @@ display: none; } -.layerControlDijit .menuLink { - color: #369; - text-decoration: none; +/* sublayer menu */ + +.layerControlDijit .layerControlSublayer .layerControlTable td.layerControlTableMenu { + padding-right: 20px; } -.layerControlDijit .menuLink:hover { - color: #5196DB; - text-decoration: underline; - cursor: pointer; +.layerControlDijit .menuClickNode.hidden { + display: none; } diff --git a/viewer/js/gis/dijit/LayerControl/nls/es/resource.js b/viewer/js/gis/dijit/LayerControl/nls/es/resource.js new file mode 100644 index 000000000..f877b51f5 --- /dev/null +++ b/viewer/js/gis/dijit/LayerControl/nls/es/resource.js @@ -0,0 +1,14 @@ +define ({ + noLegend: 'Sin Leyenda', + moveUp: 'Ascender', + moveDown: 'Mover hacia abajo', + zoomTo: 'Amplía a Capa', + transparency: 'Transparencia', + metadata: 'Metadatos', + layerSwipe: 'Flagelo capa', + layerSwipeVertical: 'Vertical', + layerSwipeHorizontal: 'Horizontal', + layerSwipeScope: 'Alcance', + dynamicSublayersOn: 'Abra todas las subcapas', + dynamicSublayersOff: 'Apagar todas las subcapas' +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/LayerControl/nls/fr/resource.js b/viewer/js/gis/dijit/LayerControl/nls/fr/resource.js new file mode 100644 index 000000000..789762185 --- /dev/null +++ b/viewer/js/gis/dijit/LayerControl/nls/fr/resource.js @@ -0,0 +1,14 @@ +define ({ + noLegend: 'Aucune légende', + moveUp: 'Déplacer vers le haut', + moveDown: 'Descendre', + zoomTo: 'Zoom sur la couche', + transparency: 'Transparence', + metadata: 'Métadonnées', + layerSwipe: 'Couche swipe', + layerSwipeVertical: 'Vertical', + layerSwipeHorizontal: 'Horizontal', + layerSwipeScope: 'Étendue', + dynamicSublayersOn: 'Activer toutes les sous-couches', + dynamicSublayersOff: 'Éteignez toutes les sous-couches' +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/LayerControl/nls/pt-br/resource.js b/viewer/js/gis/dijit/LayerControl/nls/pt-br/resource.js new file mode 100644 index 000000000..612db0653 --- /dev/null +++ b/viewer/js/gis/dijit/LayerControl/nls/pt-br/resource.js @@ -0,0 +1,21 @@ +// internationalization for LayerControl +// +// http://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html +// +// if you would like to add a locale please create an issue at +// https://github.com/cmv/cmv-app/issues and someone will assist +// if need be or checkout the link above and submit a PR +define({ + noLegend: 'Sem Legenda', + moveUp: 'Mover para Cima', + moveDown: 'Mover para Baixo', + zoomTo: 'Zoom para a Camada', + transparency: 'Transparência', + metadata: 'Metadados', + layerSwipe: 'Cortina de Camada', + layerSwipeVertical: 'Vertical', + layerSwipeHorizontal: 'Horizontal', + layerSwipeScope: 'Escopo', + dynamicSublayersOn: 'Liga todas Subcamadas', + dynamicSublayersOff: 'Desliga todas Subcamadas' +}); diff --git a/viewer/js/gis/dijit/LayerControl/nls/pt-pt/resource.js b/viewer/js/gis/dijit/LayerControl/nls/pt-pt/resource.js new file mode 100644 index 000000000..e66ea4143 --- /dev/null +++ b/viewer/js/gis/dijit/LayerControl/nls/pt-pt/resource.js @@ -0,0 +1,21 @@ +// internationalization for LayerControl +// +// http://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html +// +// if you would like to add a locale please create an issue at +// https://github.com/cmv/cmv-app/issues and someone will assist +// if need be or checkout the link above and submit a PR +define({ + noLegend: 'Sem legenda', + moveUp: 'Mover para cima', + moveDown: 'Mover para baixo', + zoomTo: 'Aproximar à Camada', + transparency: 'Transparência', + metadata: 'Metadados', + layerSwipe: 'Deslizar camada', + layerSwipeVertical: 'Vertical', + layerSwipeHorizontal: 'Horizontal', + layerSwipeScope: 'Janela', + dynamicSublayersOn: 'Activar todas as subcamadas', + dynamicSublayersOff: 'Desligar todas as subcamadas' +}); diff --git a/viewer/js/gis/dijit/LayerControl/nls/resource.js b/viewer/js/gis/dijit/LayerControl/nls/resource.js index 889ba522d..c371d3507 100644 --- a/viewer/js/gis/dijit/LayerControl/nls/resource.js +++ b/viewer/js/gis/dijit/LayerControl/nls/resource.js @@ -1,13 +1,13 @@ // internationalization for LayerControl // -// http://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html +// https://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html // // if you would like to add a locale please create an issue at // https://github.com/cmv/cmv-app/issues and someone will assist // if need be or checkout the link above and submit a PR define({ root: { - noLegend: 'No Legend', + noLegend: 'No Legend', moveUp: 'Move Up', moveDown: 'Move Down', zoomTo: 'Zoom to Layer', @@ -19,5 +19,9 @@ define({ layerSwipeScope: 'Scope', dynamicSublayersOn: 'Turn On All Sublayers', dynamicSublayersOff: 'Turn Off All Sublayers' - } + }, + 'es': true, + 'fr': true, + 'pt-br': true, + 'pt-pt': true }); diff --git a/viewer/js/gis/dijit/LayerControl/plugins/LayerMenu.js b/viewer/js/gis/dijit/LayerControl/plugins/LayerMenu.js index ac2dea328..1908610bb 100644 --- a/viewer/js/gis/dijit/LayerControl/plugins/LayerMenu.js +++ b/viewer/js/gis/dijit/LayerControl/plugins/LayerMenu.js @@ -25,7 +25,7 @@ define([ controlOptions = control.controlOptions, controller = control.controller, layerType = control._layerType, - menu = this; + self = this; //reorder menu items if ((layerType === 'vector' && controller.vectorReorder) || (layerType === 'overlay' && controller.overlayReorder)) { control._reorderUp = new MenuItem({ @@ -34,23 +34,23 @@ define([ controller._moveUp(control); } }); - menu.addChild(control._reorderUp); + self.addChild(control._reorderUp); control._reorderDown = new MenuItem({ label: i18n.moveDown, onClick: function () { controller._moveDown(control); } }); - menu.addChild(control._reorderDown); - menu.addChild(new MenuSeparator()); + self.addChild(control._reorderDown); + self.addChild(new MenuSeparator()); } // toggle all dynamic sublayers if (control._dynamicToggleMenuItems) { - control._dynamicToggleMenuItems(menu); + control._dynamicToggleMenuItems(self); } //zoom to layer if ((controlOptions.noZoom !== true && controller.noZoom !== true) || (controller.noZoom === true && controlOptions.noZoom === false)) { - menu.addChild(new MenuItem({ + self.addChild(new MenuItem({ label: i18n.zoomTo, onClick: function () { controller._zoomToLayer(layer); @@ -59,7 +59,7 @@ define([ } //transparency if ((controlOptions.noTransparency !== true && controller.noTransparency !== true) || (controller.noTransparency === true && controlOptions.noTransparency === false)) { - menu.addChild(new Transparency({ + self.addChild(new Transparency({ label: i18n.transparency, layer: layer })); @@ -87,7 +87,7 @@ define([ } })); } - menu.addChild(new PopupMenuItem({ + self.addChild(new PopupMenuItem({ label: i18n.layerSwipe, popup: swipeMenu })); @@ -95,8 +95,8 @@ define([ // metadata link // service url if (controlOptions.metadataUrl === true && layer.url) { - menu.addChild(new MenuSeparator()); - menu.addChild(new MenuItem({ + self.addChild(new MenuSeparator()); + self.addChild(new MenuItem({ label: i18n.metadata, onClick: function () { window.open(layer.url, '_blank'); @@ -105,8 +105,8 @@ define([ } // custom url if (controlOptions.metadataUrl && typeof controlOptions.metadataUrl === 'string') { - menu.addChild(new MenuSeparator()); - menu.addChild(new MenuItem({ + self.addChild(new MenuSeparator()); + self.addChild(new MenuItem({ label: i18n.metadata, onClick: function () { window.open(controlOptions.metadataUrl, '_blank'); @@ -114,10 +114,10 @@ define([ })); } //if last child is a separator remove it - var lastChild = menu.getChildren()[menu.getChildren().length - 1]; + var lastChild = self.getChildren()[self.getChildren().length - 1]; if (lastChild && lastChild.isInstanceOf(MenuSeparator)) { - menu.removeChild(lastChild); + self.removeChild(lastChild); } } }); -}); \ No newline at end of file +}); diff --git a/viewer/js/gis/dijit/LayerControl/plugins/Transparency.js b/viewer/js/gis/dijit/LayerControl/plugins/Transparency.js index d4a9e591e..fcabf5e8b 100644 --- a/viewer/js/gis/dijit/LayerControl/plugins/Transparency.js +++ b/viewer/js/gis/dijit/LayerControl/plugins/Transparency.js @@ -20,6 +20,7 @@ define([ HorizontalSlider, HorizontalRuleLabels ) { + return declare(PopupMenuItem, { layer: null, constructor: function (options) { diff --git a/viewer/js/gis/dijit/LayerControl/plugins/legendUtil.js b/viewer/js/gis/dijit/LayerControl/plugins/legendUtil.js index ef23f0c1f..830a71792 100644 --- a/viewer/js/gis/dijit/LayerControl/plugins/legendUtil.js +++ b/viewer/js/gis/dijit/LayerControl/plugins/legendUtil.js @@ -1,3 +1,4 @@ +/*eslint camelcase: 0*/ define([ 'dojo/_base/array', 'dojo/_base/lang', @@ -30,8 +31,9 @@ define([ esriBundle, i18n ) { - 'use strict'; + esriBundle.widgets.legend.NLS_noLegend = i18n.noLegend; + return { ///////////////////// // utility methods // @@ -52,17 +54,26 @@ define([ return false; } } + return false; }, // request legend json _legendRequest: function (layer, expandNode, callback, errback) { + var content = { + f: 'json', + token: (typeof layer._getToken === 'function') ? layer._getToken() : null + }, + options = {disableIdentityLookup: false, + usePost: false, + useProxy: false}; + if (layer.layerDrawingOptions && layer.layerDrawingOptions.length > 0) { + content.dynamicLayers = this._createDynamicLayerParameter(layer); + options.usePost = true; + } esriRequest({ url: layer.url + '/legend', callbackParamName: 'callback', - content: { - f: 'json', - token: (typeof layer._getToken === 'function') ? layer._getToken() : null - } - }).then( + content: content + }, options).then( lang.hitch(this, callback, layer, expandNode), lang.hitch(this, errback, layer, expandNode) ); @@ -71,7 +82,7 @@ define([ _arcgisLegendRequest: function (layer, expandNode, callback, errback) { var index = layer.url.toLowerCase().indexOf('/rest/'); var soap = layer.url.substring(0, index) + layer.url.substring(index + 5, layer.url.length); - var url = 'http://utility.arcgis.com/sharing/tools/legend?soapUrl=' + window.escape(soap); + var url = 'https://utility.arcgis.com/sharing/tools/legend?soapUrl=' + window.escape(soap); if (!has('ie') || has('ie') > 8) { url += '&returnbytes=true'; } @@ -170,14 +181,18 @@ define([ domConst.place(this._image(legend, layerId, layer), symbol); }, this); - // place legend in the appropriate sublayer expandNode - // or if a single layer use control expandNode - if (layer.layerInfos.length > 1) { - var sublayerExpandNode = registry.byId(layer.id + '-' + _layer.layerId + '-sublayer-control').expandNode; - html.set(sublayerExpandNode, ''); //clear "No Legend" placeholder - domConst.place(table, sublayerExpandNode); - } else { - domConst.place(table, expandNode); + if (layer.layerInfos.reduce(function (prior, curr) { + return (curr.id === _layer.layerId) || prior; + }, false)) { + // place legend in the appropriate sublayer expandNode + // or if a single layer use control expandNode + if (layer.layerInfos.length > 1) { + var sublayerExpandNode = registry.byId(layer.id + '-' + _layer.layerId + '-sublayer-control').expandNode; + html.set(sublayerExpandNode, ''); //clear "No Legend" placeholder + domConst.place(table, sublayerExpandNode); + } else { + domConst.place(table, expandNode); + } } }, this); }, @@ -298,6 +313,31 @@ define([ // place legend in expandNode domConst.place(table, expandNode); }, this); + }, + _createDynamicLayerParameter: function (layer) { + if (layer.dynamicLayerInfos && layer.dynamicLayerInfos.length > 0 || layer.layerDrawingOptions && layer.layerDrawingOptions.length > 0) { + layer.dynamicLayerInfos = layer.createDynamicLayerInfosFromLayerInfos(); + var dlis = layer.dynamicLayerInfos, + param = []; + dlis.forEach(function (dli) { + if (!dli.subLayerIds) { + var e, i = dli.id; + e = { + id: i, + name: dli.name + }; + if (dli.source) { + e.source = dli.source.toJson(); + } + if (layer.layerDrawingOptions && layer.layerDrawingOptions[i]) { + e.drawingInfo = layer.layerDrawingOptions[i].toJson(); + } + param.push(e); + } + }, this); + return JSON.stringify(param); + } + return null; } }; }); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Legend.js b/viewer/js/gis/dijit/Legend.js new file mode 100644 index 000000000..1cd5b92ba --- /dev/null +++ b/viewer/js/gis/dijit/Legend.js @@ -0,0 +1,31 @@ +define([ + 'dojo/_base/declare', + 'dijit/_WidgetBase', + 'dojo/_base/lang', + 'esri/dijit/Legend' +], function ( + declare, + _WidgetBase, + lang, + Legend +) { + return declare([_WidgetBase], { + startup: function () { + this.inherited(arguments); + + this.legend = new Legend({ + arrangement: this.arrangement || Legend.ALIGN_LEFT, + autoUpdate: this.autoUpdate || true, + id: this.id + '_legend', + layerInfos: this.layerInfos, + map: this.map, + respectCurrentMapScale: this.respectCurrentMapScale || true + }, this.domNode); + this.legend.startup(); + + this.map.on('update-end', lang.hitch(this, function () { + this.legend.refresh(); + })); + } + }); +}); diff --git a/viewer/js/gis/dijit/Locale.js b/viewer/js/gis/dijit/Locale.js new file mode 100644 index 000000000..32322fc58 --- /dev/null +++ b/viewer/js/gis/dijit/Locale.js @@ -0,0 +1,187 @@ +define([ + 'dojo/_base/declare', + 'dijit/_WidgetBase', + 'dijit/_TemplatedMixin', + + 'dojo/_base/lang', + 'dojo/on', + 'dojo/dom-style', + 'dojo/_base/array', + 'dojo/_base/kernel', + 'dojo/io-query', + + 'dijit/form/DropDownButton', + 'dijit/DropDownMenu', + 'dijit/MenuItem', + + './Locale/countries', + + 'dojo/text!./Locale/templates/Locale.html', + 'dojo/i18n!./Locale/nls/resource', + + 'xstyle/css!flag-icon-css/css/flag-icon.min.css', + 'xstyle/css!./Locale/css/Locale.css' +], function ( + declare, + _WidgetBase, + _TemplatedMixin, + + lang, + on, + domStyle, + array, + kernel, + ioQuery, + + DropDownButton, + DropDownMenu, + MenuItem, + + countries, + + template, + i18n +) { + + return declare([_WidgetBase, _TemplatedMixin], { + templateString: template, + i18n: i18n, + baseClass: 'cmvLocaleDijit', + + currentLocale: null, + + includeFlag: true, + includeCountry: true, + includeLanguage: true, + + languages: { + 'en': 'English', + 'es': 'Español', + 'fr': 'Français', + 'pt': 'Português' + }, + + locales: [ + 'es-ar', + 'es-bo', + 'pt-br', + 'en-ca', + 'fr-ca', + 'es-cl', + 'es-co', + 'es-cr', + 'es-do', + 'es-ec', + 'es-sv', + 'fr-FR', + 'es-gt', + 'fr-ht', + 'es-hn', + 'en-in', + 'es-mx', + 'es-pa', + 'es-pe', + 'es-pr', + 'pt-pt', + 'es-py', + 'es-es', + 'en-gb', + 'en-us', + 'es-us', + 'es-uy', + 'es-ve' + ], + + postCreate: function () { + this.inherited(arguments); + + this.currentLocale = kernel.locale; + + if (this.parentWidget) { + if (this.parentWidget.toggleable) { + domStyle.set(this.localeLabelContainer, 'display', 'block'); + } + } + + var menu = new DropDownMenu({ + baseClass: 'localeMenu' + }); + + array.forEach(this.locales, lang.hitch(this, function (locale) { + var vals = locale.split('-'); + + // only include supported languages + var language = this.languages[vals[0]]; + if (language) { + var label = '', country = null, icon = null; + if (vals[1]) { + if (this.includeFlag) { + icon = 'flag-icon flag-icon-' + vals[1].toLowerCase(); + } + country = countries[vals[1].toUpperCase()]; + if (country && this.includeCountry) { + label = country; + } + } + if (this.includeLanguage) { + if (label.length > 0) { + label += ' - '; + } + label += language; + } + var menuItem = new MenuItem({ + id: locale, + label: label, + iconClass: icon, + onClick: lang.hitch(this, 'switchLocale', locale) + }); + menu.addChild(menuItem); + } + })); + menu.startup(); + + var vals = this.currentLocale.split('-'); + var language = this.languages[vals[0]]; + var label = '', country = null; + if (vals[1]) { + if (this.includeFlag) { + label = '
'; + } + country = countries[vals[1].toUpperCase()]; + if (country && this.includeCountry) { + label += country; + } + if (this.includeLanguage) { + if (country && this.includeCountry) { + label += ' - '; + } + label += language; + } + } + + var button = new DropDownButton({ + label: label, + dropDown: menu + }); + + this.localeDropDownContainer.appendChild(button.domNode); + }, + + switchLocale: function (newLocale) { + if (newLocale !== this.currentLocale) { + var uri = window.location.href, qsObj = {}; + if (uri.indexOf('?') > -1) { + var qs = uri.substring(uri.indexOf('?') + 1, uri.length); + qsObj = ioQuery.queryToObject(qs); + } + + // set the new locale + qsObj.locale = newLocale; + + // reload the page + window.location = window.location.pathname + '?' + ioQuery.objectToQuery(qsObj); + + } + } + }); +}); diff --git a/viewer/js/gis/dijit/Locale/countries.js b/viewer/js/gis/dijit/Locale/countries.js new file mode 100644 index 000000000..2313b1ee2 --- /dev/null +++ b/viewer/js/gis/dijit/Locale/countries.js @@ -0,0 +1,247 @@ +define ({ + 'AF': 'Afghanistan', + 'AX': 'Åland Islands', + 'AL': 'Albania', + 'DZ': 'Algeria', + 'AS': 'American Samoa', + 'AD': 'Andorra', + 'AO': 'Angola', + 'AI': 'Anguilla', + 'AQ': 'Antarctica', + 'AG': 'Antigua and Barbuda', + 'AR': 'Argentina', + 'AM': 'Armenia', + 'AW': 'Aruba', + 'AU': 'Australia', + 'AT': 'Austria', + 'AZ': 'Azerbaijan', + 'BS': 'Bahamas', + 'BH': 'Bahrain', + 'BD': 'Bangladesh', + 'BB': 'Barbados', + 'BY': 'Belarus', + 'BE': 'Belgium', + 'BZ': 'Belize', + 'BJ': 'Benin', + 'BM': 'Bermuda', + 'BT': 'Bhutan', + 'BO': 'Bolivia', + 'BA': 'Bosnia and Herzegovina', + 'BW': 'Botswana', + 'BV': 'Bouvet Island', + 'BR': 'Brazil', + 'IO': 'British Indian Ocean Territory', + 'BN': 'Brunei Darussalam', + 'BG': 'Bulgaria', + 'BF': 'Burkina Faso', + 'BI': 'Burundi', + 'KH': 'Cambodia', + 'CM': 'Cameroon', + 'CA': 'Canada', + 'CV': 'Cape Verde', + 'KY': 'Cayman Islands', + 'CF': 'Central African Republic', + 'TD': 'Chad', + 'CL': 'Chile', + 'CN': 'China', + 'CX': 'Christmas Island', + 'CC': 'Cocos (Keeling) Islands', + 'CO': 'Colombia', + 'KM': 'Comoros', + 'CG': 'Congo', + 'CD': 'Congo, The Democratic Republic of the', + 'CK': 'Cook Islands', + 'CR': 'Costa Rica', + 'CI': 'Cote D\'Ivoire', + 'HR': 'Croatia', + 'CU': 'Cuba', + 'CY': 'Cyprus', + 'CZ': 'Czech Republic', + 'DK': 'Denmark', + 'DJ': 'Djibouti', + 'DM': 'Dominica', + 'DO': 'Dominican Republic', + 'EC': 'Ecuador', + 'EG': 'Egypt', + 'SV': 'El Salvador', + 'GQ': 'Equatorial Guinea', + 'ER': 'Eritrea', + 'EE': 'Estonia', + 'ET': 'Ethiopia', + 'FK': 'Falkland Islands (Malvinas)', + 'FO': 'Faroe Islands', + 'FJ': 'Fiji', + 'FI': 'Finland', + 'FR': 'France', + 'GF': 'French Guiana', + 'PF': 'French Polynesia', + 'TF': 'French Southern Territories', + 'GA': 'Gabon', + 'GM': 'Gambia', + 'GE': 'Georgia', + 'DE': 'Germany', + 'GH': 'Ghana', + 'GI': 'Gibraltar', + 'GR': 'Greece', + 'GL': 'Greenland', + 'GD': 'Grenada', + 'GP': 'Guadeloupe', + 'GU': 'Guam', + 'GT': 'Guatemala', + 'GG': 'Guernsey', + 'GN': 'Guinea', + 'GW': 'Guinea-Bissau', + 'GY': 'Guyana', + 'HT': 'Haiti', + 'HM': 'Heard Island and Mcdonald Islands', + 'VA': 'Holy See (Vatican City State)', + 'HN': 'Honduras', + 'HK': 'Hong Kong', + 'HU': 'Hungary', + 'IS': 'Iceland', + 'IN': 'India', + 'ID': 'Indonesia', + 'IR': 'Iran, Islamic Republic Of', + 'IQ': 'Iraq', + 'IE': 'Ireland', + 'IM': 'Isle of Man', + 'IL': 'Israel', + 'IT': 'Italy', + 'JM': 'Jamaica', + 'JP': 'Japan', + 'JE': 'Jersey', + 'JO': 'Jordan', + 'KZ': 'Kazakhstan', + 'KE': 'Kenya', + 'KI': 'Kiribati', + 'KP': 'Democratic People\'s Republic of Korea', + 'KR': 'Korea, Republic of', + 'XK': 'Kosovo', + 'KW': 'Kuwait', + 'KG': 'Kyrgyzstan', + 'LA': 'Lao People\'s Democratic Republic', + 'LV': 'Latvia', + 'LB': 'Lebanon', + 'LS': 'Lesotho', + 'LR': 'Liberia', + 'LY': 'Libyan Arab Jamahiriya', + 'LI': 'Liechtenstein', + 'LT': 'Lithuania', + 'LU': 'Luxembourg', + 'MO': 'Macao', + 'MK': 'Macedonia, The Former Yugoslav Republic of', + 'MG': 'Madagascar', + 'MW': 'Malawi', + 'MY': 'Malaysia', + 'MV': 'Maldives', + 'ML': 'Mali', + 'MT': 'Malta', + 'MH': 'Marshall Islands', + 'MQ': 'Martinique', + 'MR': 'Mauritania', + 'MU': 'Mauritius', + 'YT': 'Mayotte', + 'MX': 'Mexico', + 'FM': 'Micronesia, Federated States of', + 'MD': 'Moldova, Republic of', + 'MC': 'Monaco', + 'MN': 'Mongolia', + 'ME': 'Montenegro', + 'MS': 'Montserrat', + 'MA': 'Morocco', + 'MZ': 'Mozambique', + 'MM': 'Myanmar', + 'NA': 'Namibia', + 'NR': 'Nauru', + 'NP': 'Nepal', + 'NL': 'Netherlands', + 'AN': 'Netherlands Antilles', + 'NC': 'New Caledonia', + 'NZ': 'New Zealand', + 'NI': 'Nicaragua', + 'NE': 'Niger', + 'NG': 'Nigeria', + 'NU': 'Niue', + 'NF': 'Norfolk Island', + 'MP': 'Northern Mariana Islands', + 'NO': 'Norway', + 'OM': 'Oman', + 'PK': 'Pakistan', + 'PW': 'Palau', + 'PS': 'Palestinian Territory, Occupied', + 'PA': 'Panama', + 'PG': 'Papua New Guinea', + 'PY': 'Paraguay', + 'PE': 'Peru', + 'PH': 'Philippines', + 'PN': 'Pitcairn', + 'PL': 'Poland', + 'PT': 'Portugal', + 'PR': 'Puerto Rico', + 'QA': 'Qatar', + 'RE': 'Reunion', + 'RO': 'Romania', + 'RU': 'Russian Federation', + 'RW': 'Rwanda', + 'SH': 'Saint Helena', + 'KN': 'Saint Kitts and Nevis', + 'LC': 'Saint Lucia', + 'PM': 'Saint Pierre and Miquelon', + 'VC': 'Saint Vincent and the Grenadines', + 'WS': 'Samoa', + 'SM': 'San Marino', + 'ST': 'Sao Tome and Principe', + 'SA': 'Saudi Arabia', + 'SN': 'Senegal', + 'RS': 'Serbia', + 'SC': 'Seychelles', + 'SL': 'Sierra Leone', + 'SG': 'Singapore', + 'SK': 'Slovakia', + 'SI': 'Slovenia', + 'SB': 'Solomon Islands', + 'SO': 'Somalia', + 'ZA': 'South Africa', + 'GS': 'South Georgia and the South Sandwich Islands', + 'ES': 'Spain', + 'LK': 'Sri Lanka', + 'SD': 'Sudan', + 'SR': 'Suriname', + 'SJ': 'Svalbard and Jan Mayen', + 'SZ': 'Swaziland', + 'SE': 'Sweden', + 'CH': 'Switzerland', + 'SY': 'Syrian Arab Republic', + 'TW': 'Taiwan', + 'TJ': 'Tajikistan', + 'TZ': 'Tanzania, United Republic of', + 'TH': 'Thailand', + 'TL': 'Timor-Leste', + 'TG': 'Togo', + 'TK': 'Tokelau', + 'TO': 'Tonga', + 'TT': 'Trinidad and Tobago', + 'TN': 'Tunisia', + 'TR': 'Turkey', + 'TM': 'Turkmenistan', + 'TC': 'Turks and Caicos Islands', + 'TV': 'Tuvalu', + 'UG': 'Uganda', + 'UA': 'Ukraine', + 'AE': 'United Arab Emirates', + 'GB': 'United Kingdom', + 'US': 'United States', + 'UM': 'United States Minor Outlying Islands', + 'UY': 'Uruguay', + 'UZ': 'Uzbekistan', + 'VU': 'Vanuatu', + 'VE': 'Venezuela', + 'VN': 'Viet Nam', + 'VG': 'Virgin Islands, British', + 'VI': 'Virgin Islands, U.S.', + 'WF': 'Wallis and Futuna', + 'EH': 'Western Sahara', + 'YE': 'Yemen', + 'ZM': 'Zambia', + 'ZW': 'Zimbabwe' +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Locale/css/Locale.css b/viewer/js/gis/dijit/Locale/css/Locale.css new file mode 100644 index 000000000..295d669fc --- /dev/null +++ b/viewer/js/gis/dijit/Locale/css/Locale.css @@ -0,0 +1,14 @@ +.cmvLocaleDijit label { + font-weight: bold; +} +.flag-icon { + width: 20px; + height: 15px; + margin-right: 5px; + margin-top: -1px; + border: 1px solid #DDD; +} + +.localeMenuPopup { + max-height: 300px; +} \ No newline at end of file diff --git a/viewer/js/gis/dijit/Locale/nls/es/resource.js b/viewer/js/gis/dijit/Locale/nls/es/resource.js new file mode 100644 index 000000000..ca3c987cb --- /dev/null +++ b/viewer/js/gis/dijit/Locale/nls/es/resource.js @@ -0,0 +1,3 @@ +define ({ + selectLocale: 'Seleccione su Lugar:' +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Locale/nls/fr/resource.js b/viewer/js/gis/dijit/Locale/nls/fr/resource.js new file mode 100644 index 000000000..0c23e350e --- /dev/null +++ b/viewer/js/gis/dijit/Locale/nls/fr/resource.js @@ -0,0 +1,3 @@ +define ({ + selectLocale: 'Sélectionnez votre lieu :' +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Locale/nls/pt-br/resource.js b/viewer/js/gis/dijit/Locale/nls/pt-br/resource.js new file mode 100644 index 000000000..eac84670c --- /dev/null +++ b/viewer/js/gis/dijit/Locale/nls/pt-br/resource.js @@ -0,0 +1,3 @@ +define ({ + selectLocale: 'Escolha a sua localidade:' +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Locale/nls/pt-pt/resource.js b/viewer/js/gis/dijit/Locale/nls/pt-pt/resource.js new file mode 100644 index 000000000..eac84670c --- /dev/null +++ b/viewer/js/gis/dijit/Locale/nls/pt-pt/resource.js @@ -0,0 +1,3 @@ +define ({ + selectLocale: 'Escolha a sua localidade:' +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Locale/nls/resource.js b/viewer/js/gis/dijit/Locale/nls/resource.js new file mode 100644 index 000000000..239076ecf --- /dev/null +++ b/viewer/js/gis/dijit/Locale/nls/resource.js @@ -0,0 +1,9 @@ +define ({ + root: { + selectLocale: 'Select Your Locale:' + }, + 'es': true, + 'fr': true, + 'pt-br': true, + 'pt-pt': true +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Locale/templates/Locale.html b/viewer/js/gis/dijit/Locale/templates/Locale.html new file mode 100644 index 000000000..e07a68851 --- /dev/null +++ b/viewer/js/gis/dijit/Locale/templates/Locale.html @@ -0,0 +1,6 @@ +
+
+ +
+
+
\ No newline at end of file diff --git a/viewer/js/gis/dijit/LocateButton.js b/viewer/js/gis/dijit/LocateButton.js index e2f6f6387..aeb725496 100644 --- a/viewer/js/gis/dijit/LocateButton.js +++ b/viewer/js/gis/dijit/LocateButton.js @@ -1,61 +1,62 @@ define([ - 'dojo/_base/declare', - 'dojo/_base/lang', - 'esri/dijit/LocateButton', - 'esri/renderers/SimpleRenderer', - 'esri/symbols/PictureMarkerSymbol', - 'esri/layers/GraphicsLayer', - 'esri/InfoTemplate', - 'dojo/topic' + 'dojo/_base/declare', + 'dojo/_base/lang', + 'esri/dijit/LocateButton', + 'esri/renderers/SimpleRenderer', + 'esri/symbols/PictureMarkerSymbol', + 'esri/layers/GraphicsLayer', + 'esri/InfoTemplate', + 'dojo/topic' ], function (declare, lang, LocateButton, SimpleRenderer, PictureMarkerSymbol, GraphicsLayer, InfoTemplate, topic) { - return declare(null, { - growlTemplate: 'latitude: {latitude}
longitude: {longitude}
accuracy: {accuracy}
altitude: {altitude}
altitude accuracy: {altitudeAccuracy}
heading: {heading}
speed: {speed}', - constructor: function (options, node) { - this.options = options; - this.parentNode = node; - }, - startup: function () { - var symbol = new PictureMarkerSymbol('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAmCAYAAACoPemuAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABJhJREFUeNrcmN9PW2UYx7/n9ATKj7QMMUCxmSxlCRI3BzF6MRO9WOyVN5sJFxqvNCa7MmbphTG78Iprwx+weEMiF8bdLNFojBhNDEwu3ObWjo2uLUXKaIFSCqdnz7e8hx1WdOcUij+e5ElLOe3zyfd93ud9nlezLAte7LOv0S4vZ8VPi0eU72dx5bPiU+Jr9j8+fevpcTS3YALUIy/viUdRn10TvyK+cChgTwL5dOCZNqA7CARbgIB//+8VSkB+A8jmgdw6YFb2AgrcQt1gAsUli4m3E6gnAAx0A61N3qQqloE7WZGqsAvIZR0TuCnPYAJ1UV4u8H2oAzhZB9B+gLcFML2y+9GkwI27BhOomL10g71AfxcO1eaWgJuZx0srcGNPBbOV4tK9emInjxphzL9f7u4ubY1y+j45VV2+RkLR+NuMoeyCil0LpnZfzF6+RkI54RhLWUwx1CjGktDORD/snPo7YyzGZGzF8BhMkUaZV9x9R22M6duRKGqrpjvUqtapg5aEeowxGdvJoquzr6rWgEe1uJ8rFrSy+EYFOp3v+ZnlEW5gr2rthjqQq8eMF7UYvGRBL5jwFbZhFCs76rfqqAQMbAd8MP0aKroGy61qZFhcrf551lBdQvXs8wK1VoFvoYym+5vwT6ceBrMrq36YW+gOtJRGng/ljzej1NOEcrsO0y0cGRTYacNuW9yWB0agUoSaLpiBianfw5l7ydbBvle0Yi6Dn+IT1s8n+ouj588nR441F55rxmaLBlNzWT6URXbB/qpLqAETtbh8VGrih9nwYHi47e33TyErx3Lhfhc6Zl7Ufrs62TaxfiXc9eEHCS4rl1RzoZqDIaJ73UHbbGkkp64/WAqm/7jROvAacGtTzj5Zgrvii5YJq/N1pH/8tvX6rTtBPrtdx071DGaKYkz0zFLOf/LZF7TMn0BqXlqaJJBZLCOVzwEbq7CWwlpmPunns/yO1zhG3cVHEn0rn8bq3DBK0s4UimsoPlzZaboyImFB1tY06/55z4r5JFdYEno7g6W5+HfW9vwGyullbKSkl7knaiXyVdcqv1q9faESn/W53JUHAqPETOgz/eF8KDJYnPnmC6wncrASotRN6aFnRKnclwi9ca545tRQns8adSoWt3t0N8bdxeLJOjX6zrvJQMfq+vJXFy1c/Rz4fhz68kdW3zn/+ugnl5N8hs9qLhVzMMQNBRZh4+amZDCLuf1ZPEc6/YWuSx8npt+MBrMPUn5UKugOXSqNDL+0W2CrpcJD8+gE49wX5TQTPuZSZlGAFZ3Fk0t1/OWhUnFk6EBHEo0MymYNNYzGOGJxWHB7XjIgKzqDdxrYsksCE91QS+6lRjA2GZRN6dJrc5S6xt6bI5YX0xRgEyFFKTrf6x6haIyt+n8OJ2v2ruSEXC1BJD9qY0zGdrLo6i5hwVbtdvbowW6k96i18GQdI+kah1HOfUdljKVaHabUeE2BVaTVwZPDqGPrNswYwzH4jql8r6386i5hku85jDYSzh54HVcFU//NK4JGX6ow0VVOeb9U+VdfQzX44m7cmej/r6vOf+py+JEAAwDRMD/uB0XQuQAAAABJRU5ErkJggg==', 38, 38); - this.graphics = new GraphicsLayer({ - id: 'GeoLocationGraphics' - }); - var renderer = new SimpleRenderer(symbol); - renderer.label = 'GPS Position'; - renderer.description = 'GPS Position'; - this.graphics.setRenderer(renderer); - this.options.map.addLayer(this.graphics); - this.options.graphicsLayer = this.graphics; - this.options.infoTemplate = new InfoTemplate('GPS Position', '${*}'); - this.options.symbol = null; - this.locateButton = new LocateButton(this.options, this.parentNode); - this.locateButton.startup(); - this.locateButton.on('locate', lang.hitch(this, '_growlLocation')); - }, - _growlLocation: function (evt) { - var stats = { - accuracy: (evt.position.coords.accuracy) ? evt.position.coords.accuracy : '', - altitude: (evt.position.coords.altitude) ? evt.position.coords.altitude : '', - altitudeAccuracy: (evt.position.coords.altitudeAccuracy) ? evt.position.coords.altitudeAccuracy : '', - heading: (evt.position.coords.heading) ? evt.position.coords.heading : '', - latitude: (evt.position.coords.latitude) ? evt.position.coords.latitude : '', - longitude: (evt.position.coords.longitude) ? evt.position.coords.longitude : '', - speed: (evt.position.coords.speed) ? evt.position.coords.speed : '' - }; + return declare(null, { + growlTemplate: 'latitude: {latitude}
longitude: {longitude}
accuracy: {accuracy}
altitude: {altitude}
altitude accuracy: {altitudeAccuracy}
heading: {heading}
speed: {speed}', + constructor: function (options, node) { + this.options = options; + this.parentNode = node; + }, + startup: function () { + var symbol = new PictureMarkerSymbol('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAmCAYAAACoPemuAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABJhJREFUeNrcmN9PW2UYx7/n9ATKj7QMMUCxmSxlCRI3BzF6MRO9WOyVN5sJFxqvNCa7MmbphTG78Iprwx+weEMiF8bdLNFojBhNDEwu3ObWjo2uLUXKaIFSCqdnz7e8hx1WdOcUij+e5ElLOe3zyfd93ud9nlezLAte7LOv0S4vZ8VPi0eU72dx5bPiU+Jr9j8+fevpcTS3YALUIy/viUdRn10TvyK+cChgTwL5dOCZNqA7CARbgIB//+8VSkB+A8jmgdw6YFb2AgrcQt1gAsUli4m3E6gnAAx0A61N3qQqloE7WZGqsAvIZR0TuCnPYAJ1UV4u8H2oAzhZB9B+gLcFML2y+9GkwI27BhOomL10g71AfxcO1eaWgJuZx0srcGNPBbOV4tK9emInjxphzL9f7u4ubY1y+j45VV2+RkLR+NuMoeyCil0LpnZfzF6+RkI54RhLWUwx1CjGktDORD/snPo7YyzGZGzF8BhMkUaZV9x9R22M6duRKGqrpjvUqtapg5aEeowxGdvJoquzr6rWgEe1uJ8rFrSy+EYFOp3v+ZnlEW5gr2rthjqQq8eMF7UYvGRBL5jwFbZhFCs76rfqqAQMbAd8MP0aKroGy61qZFhcrf551lBdQvXs8wK1VoFvoYym+5vwT6ceBrMrq36YW+gOtJRGng/ljzej1NOEcrsO0y0cGRTYacNuW9yWB0agUoSaLpiBianfw5l7ydbBvle0Yi6Dn+IT1s8n+ouj588nR441F55rxmaLBlNzWT6URXbB/qpLqAETtbh8VGrih9nwYHi47e33TyErx3Lhfhc6Zl7Ufrs62TaxfiXc9eEHCS4rl1RzoZqDIaJ73UHbbGkkp64/WAqm/7jROvAacGtTzj5Zgrvii5YJq/N1pH/8tvX6rTtBPrtdx071DGaKYkz0zFLOf/LZF7TMn0BqXlqaJJBZLCOVzwEbq7CWwlpmPunns/yO1zhG3cVHEn0rn8bq3DBK0s4UimsoPlzZaboyImFB1tY06/55z4r5JFdYEno7g6W5+HfW9vwGyullbKSkl7knaiXyVdcqv1q9faESn/W53JUHAqPETOgz/eF8KDJYnPnmC6wncrASotRN6aFnRKnclwi9ca545tRQns8adSoWt3t0N8bdxeLJOjX6zrvJQMfq+vJXFy1c/Rz4fhz68kdW3zn/+ugnl5N8hs9qLhVzMMQNBRZh4+amZDCLuf1ZPEc6/YWuSx8npt+MBrMPUn5UKugOXSqNDL+0W2CrpcJD8+gE49wX5TQTPuZSZlGAFZ3Fk0t1/OWhUnFk6EBHEo0MymYNNYzGOGJxWHB7XjIgKzqDdxrYsksCE91QS+6lRjA2GZRN6dJrc5S6xt6bI5YX0xRgEyFFKTrf6x6haIyt+n8OJ2v2ruSEXC1BJD9qY0zGdrLo6i5hwVbtdvbowW6k96i18GQdI+kah1HOfUdljKVaHabUeE2BVaTVwZPDqGPrNswYwzH4jql8r6386i5hku85jDYSzh54HVcFU//NK4JGX6ow0VVOeb9U+VdfQzX44m7cmej/r6vOf+py+JEAAwDRMD/uB0XQuQAAAABJRU5ErkJggg==', 38, 38); + this.graphics = new GraphicsLayer({ + id: 'GeoLocationGraphics' + }); + var renderer = new SimpleRenderer(symbol); + renderer.label = 'GPS Position'; + renderer.description = 'GPS Position'; + this.graphics.setRenderer(renderer); + this.options.map.addLayer(this.graphics); + this.options.graphicsLayer = this.graphics; + this.options.infoTemplate = new InfoTemplate('GPS Position', '${*}'); + this.options.symbol = null; - if (this.graphics.graphics.length > 0) { - this.graphics.graphics[0].attributes = stats; - } + this.locateButton = new LocateButton(this.options, this.parentNode); + this.locateButton.startup(); + this.locateButton.on('locate', lang.hitch(this, '_growlLocation')); + }, + _growlLocation: function (evt) { + var stats = { + accuracy: (evt.position.coords.accuracy) ? evt.position.coords.accuracy : '', + altitude: (evt.position.coords.altitude) ? evt.position.coords.altitude : '', + altitudeAccuracy: (evt.position.coords.altitudeAccuracy) ? evt.position.coords.altitudeAccuracy : '', + heading: (evt.position.coords.heading) ? evt.position.coords.heading : '', + latitude: (evt.position.coords.latitude) ? evt.position.coords.latitude : '', + longitude: (evt.position.coords.longitude) ? evt.position.coords.longitude : '', + speed: (evt.position.coords.speed) ? evt.position.coords.speed : '' + }; - if (this.options.publishGPSPosition) { - topic.publish('growler/growl', { - title: 'GPS Position', - message: lang.replace(this.growlTemplate, stats), - level: 'default', //can be: 'default', 'warning', 'info', 'error', 'success'. - timeout: 10000, //set to 0 for no timeout - opacity: 1.0 - }); - } - } - }); + if (this.graphics.graphics.length > 0) { + this.graphics.graphics[0].attributes = stats; + } + + if (this.options.publishGPSPosition) { + topic.publish('growler/growl', { + title: 'GPS Position', + message: lang.replace(this.growlTemplate, stats), + level: 'default', //can be: 'default', 'warning', 'info', 'error', 'success'. + timeout: 10000, //set to 0 for no timeout + opacity: 1.0 + }); + } + } + }); }); \ No newline at end of file diff --git a/viewer/js/gis/dijit/MapInfo.js b/viewer/js/gis/dijit/MapInfo.js index 380c772b5..a6d414ba2 100644 --- a/viewer/js/gis/dijit/MapInfo.js +++ b/viewer/js/gis/dijit/MapInfo.js @@ -10,7 +10,7 @@ define([ 'dojo/dom-style', 'dojo/number', 'dojo/topic', - '//cdnjs.cloudflare.com/ajax/libs/proj4js/2.3.3/proj4.js', + 'proj4js/proj4', 'xstyle/css!./MapInfo/css/MapInfo.css' ], function ( declare, @@ -23,7 +23,7 @@ define([ topic, proj4 ) { - 'use strict'; + return declare([WidgetBase, TemplatedMixin], { map: null, mode: 'map', @@ -36,6 +36,7 @@ define([ scaleLabel: '1:', zoomLabel: 'Z:', minWidth: 0, + proj4BaseURL: 'https://epsg.io/', proj4Catalog: null, proj4Wkid: null, proj4CustomURL: null, @@ -99,27 +100,26 @@ define([ this._mode = 3; } else { this._mode = 4; - // spatialreference.org uses the old - // Proj4js style so we need an alias - // https://github.com/proj4js/proj4js/issues/23 - window.Proj4js = proj4; - //load custom projection file or default to spatialreference.org - if (!this.proj4Catalog && !this.proj4Wkid && !this.proj4CustomURL) { + if (!window.proj4) { + window.proj4 = proj4; + } + if (this.proj4Wkid) { + wkid = this.proj4Wkid; + } + //load custom projection file or default to epsg.io + if (!this.proj4Catalog && !wkid && !this.proj4CustomURL) { topic.publish('viewer/handleError', { source: 'MapInfo', error: 'MapInfo error::a proj4Catalog/proj4Wkid or custom URL must be defined' }); return; } - if (this.proj4CustomURL) { - require([this.proj4CustomURL], lang.hitch(this, function () { - this._projectionLoaded = true; - this._projection = this.proj4Catalog + ':' + this.proj4Wkid; - })); - } else { - require(['http://spatialreference.org/ref/' + this.proj4Catalog.toLowerCase() + '/' + this.proj4Wkid + '/proj4js/'], lang.hitch(this, function () { + var key = this.proj4Catalog + ':' + String(wkid); + this._projection = key; + if (!proj4.defs[key]) { + var url = this.proj4CustomURL || this.proj4BaseURL + String(wkid) + '.js'; + require([url], lang.hitch(this, function () { this._projectionLoaded = true; - this._projection = this.proj4Catalog + ':' + this.proj4Wkid; })); } } @@ -169,6 +169,8 @@ define([ this._project(pnt); } break; + default: + break; } }, _project: function (pnt) { @@ -215,4 +217,4 @@ define([ return deg + '°' + minIntTxt + '\'' + secTxt + '" ' + dir; } }); -}); \ No newline at end of file +}); diff --git a/viewer/js/gis/dijit/Measurement.js b/viewer/js/gis/dijit/Measurement.js index c6acdf0ea..d1bf38917 100644 --- a/viewer/js/gis/dijit/Measurement.js +++ b/viewer/js/gis/dijit/Measurement.js @@ -35,10 +35,8 @@ define([ this.connectMapClick(); } // a measurement tool is active - } else { - if (this.mapClickMode !== 'measure') { - this.disconnectMapClick(); - } + } else if (this.mapClickMode !== 'measure') { + this.disconnectMapClick(); } }, disconnectMapClick: function () { diff --git a/viewer/js/gis/dijit/Print.js b/viewer/js/gis/dijit/Print.js index bb6a6efed..7fa56891f 100644 --- a/viewer/js/gis/dijit/Print.js +++ b/viewer/js/gis/dijit/Print.js @@ -1,3 +1,4 @@ +/*eslint no-eval: 0 */ define([ 'dojo/_base/declare', 'dijit/_WidgetBase', @@ -11,11 +12,13 @@ define([ 'dojo/dom-style', 'dojo/dom-construct', 'dojo/dom-class', + 'dojo/date/locale', 'dojo/text!./Print/templates/Print.html', 'dojo/text!./Print/templates/PrintResult.html', 'esri/tasks/PrintTemplate', 'esri/tasks/PrintParameters', 'esri/request', + 'esri/urlUtils', 'dojo/i18n!./Print/nls/resource', 'dijit/form/Form', @@ -29,7 +32,55 @@ define([ 'dijit/TooltipDialog', 'dijit/form/RadioButton', 'xstyle/css!./Print/css/Print.css' -], function (declare, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, PrintTask, Memory, lang, array, topic, Style, domConstruct, domClass, printTemplate, printResultTemplate, PrintTemplate, PrintParameters, esriRequest, i18n) { +], function (declare, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, PrintTask, Memory, lang, array, topic, Style, domConstruct, domClass, locale, printTemplate, printResultTemplate, PrintTemplate, PrintParameters, esriRequest, urlUtils, i18n) { + + // Print result dijit + var PrintResultDijit = declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], { + widgetsInTemplate: true, + templateString: printResultTemplate, + i18n: i18n, + url: null, + fileHandle: null, + resultOrder: 'last', // first or last + + postCreate: function () { + this.inherited(arguments); + this.fileHandle.then(lang.hitch(this, '_onPrintComplete'), lang.hitch(this, '_onPrintError')); + }, + _onPrintComplete: function (data) { + if (data.url) { + var proxyRule = urlUtils.getProxyRule(data.url); + if (proxyRule && proxyRule.proxyUrl) { + this.url = proxyRule.proxyUrl + '?' + data.url; + } else { + this.url = data.url; + } + this.nameNode.innerHTML = '' + this.docName + ''; + domClass.add(this.resultNode, 'printResultHover'); + } else { + this._onPrintError(this.i18n.printResults.errorMessage); + } + }, + _onPrintError: function (err) { + topic.publish('viewer/handleError', { + source: 'Print', + error: err + }); + this.nameNode.innerHTML = '' + i18n.printResults.errorMessage + ''; + domClass.add(this.resultNode, 'printResultError'); + }, + _openPrint: function () { + if (this.url !== null) { + window.open(this.url); + } + }, + _handleStatusUpdate: function (event) { + var jobStatus = event.jobInfo.jobStatus; + if (jobStatus === 'esriJobFailed') { + this._onPrintError(this.i18n.printResults.errorMessage); + } + } + }); // Main print dijit var PrintDijit = declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], { @@ -69,7 +120,7 @@ define([ }, operationalLayersInspector: function (opLayers) { array.forEach(opLayers, function (layer) { - if (layer.id == 'Measurement_graphicslayer') { + if (layer.id === 'Measurement_graphicslayer') { array.forEach(layer.featureCollection.layers, function (fcLayer) { array.forEach(fcLayer.featureSet.features, function (feature) { delete feature.attributes; @@ -92,17 +143,17 @@ define([ this.printTask = new PrintTask(this.printTaskURL, { async: data.executionType === 'esriExecutionTypeAsynchronous' }); - var Layout_Template = array.filter(data.parameters, function (param) { + var layoutTemplate = array.filter(data.parameters, function (param) { return param.name === 'Layout_Template'; }); - if (Layout_Template.length === 0) { + if (layoutTemplate.length === 0) { topic.publish('viewer/handleError', { source: 'Print', error: 'Print service parameters name for templates must be \'Layout_Template\'' }); return; } - var layoutItems = array.map(Layout_Template[0].choiceList, function (item) { + var layoutItems = array.map(layoutTemplate[0].choiceList, function (item) { return { name: item, id: item @@ -118,7 +169,7 @@ define([ if (this.defaultLayout) { this.layoutDijit.set('value', this.defaultLayout); } else { - this.layoutDijit.set('value', Layout_Template[0].defaultValue); + this.layoutDijit.set('value', layoutTemplate[0].defaultValue); } var Format = array.filter(data.parameters, function (param) { @@ -164,9 +215,7 @@ define([ var template = new PrintTemplate(); template.format = form.format; template.layout = form.layout; - /*jslint evil: true */ template.preserveScale = eval(form.preserveScale); //turns a string 'true' into true - /*jslint evil: false */ template.label = form.title; template.exportOptions = mapOnlyForm; template.layoutOptions = { @@ -183,12 +232,12 @@ define([ count: this.count.toString(), icon: (form.format === 'PDF') ? this.pdfIcon : this.imageIcon, docName: form.title, - title: form.format + ', ' + form.layout, + title: form.format + ', ' + form.layout + ', ' + locale.format(new Date(), {formatLength: 'short'}), fileHandle: fileHandle - }).placeAt(this.printResultsNode, 'last'); + }).placeAt(this.printResultsNode, this.resultOrder); - if ( this.printTask.async ) { - result.own( this.printTask.printGp.on( 'status-update', lang.hitch( result, '_handleStatusUpdate' ) ) ); + if (this.printTask.async) { + result.own(this.printTask.printGp.on('status-update', lang.hitch(result, '_handleStatusUpdate'))); } @@ -205,45 +254,5 @@ define([ } }); - // Print result dijit - var PrintResultDijit = declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], { - widgetsInTemplate: true, - templateString: printResultTemplate, - i18n: i18n, - url: null, - fileHandle: null, - postCreate: function () { - this.inherited(arguments); - this.fileHandle.then(lang.hitch(this, '_onPrintComplete'), lang.hitch(this, '_onPrintError')); - }, - _onPrintComplete: function (data) { - if (data.url) { - this.url = data.url; - this.nameNode.innerHTML = '' + this.docName + ''; - domClass.add(this.resultNode, 'printResultHover'); - } else { - this._onPrintError( this.i18n.printResults.errorMessage ); - } - }, - _onPrintError: function (err) { - topic.publish('viewer/handleError', { - source: 'Print', - error: err - }); - this.nameNode.innerHTML = '' + i18n.printResults.errorMessage + ''; - domClass.add(this.resultNode, 'printResultError'); - }, - _openPrint: function () { - if (this.url !== null) { - window.open(this.url); - } - }, - _handleStatusUpdate: function ( event ) { - var jobStatus = event.jobInfo.jobStatus; - if ( jobStatus === 'esriJobFailed' ){ - this._onPrintError( this.i18n.printResults.errorMessage ); - } - } - }); return PrintDijit; }); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Print/nls/es/resource.js b/viewer/js/gis/dijit/Print/nls/es/resource.js new file mode 100644 index 000000000..a11fa0e2b --- /dev/null +++ b/viewer/js/gis/dijit/Print/nls/es/resource.js @@ -0,0 +1,39 @@ +define ({ + title: 'Título', + format: 'Formato', + layout: 'Diseño', + settings: 'Ajustes', + mapScaleExtent: 'Escala/Extensión de mapa', + preserve: 'Preservar', + mapScale: 'escala del mapa', + mapExtent: 'extensión de mapa', + fullLayoutOptions: 'Opciones de diseño completos', + scaleBarUnits: 'Unidades barra de escala', + miles: 'Millas', + kilometers: 'Kilómetros', + meters: 'Metros', + feet: 'Pies', + includeLegend: 'Incluir la leyenda', + printQualityOptions: 'Opciones de calidad de impresión', + dpiInput: { + label: 'DPI', + invalidMessage: 'Por favor, introduzca un valor numérico.', + rangeMessage: 'Por favor, introduzca un valor entre 100 y 300.' + }, + mapOnlyOptions: 'Opciones MAP_ONLY', + width: 'Anchura', + height: 'Altura', + printButton: { + busyLabel: 'imprenta', + label: 'Impresión' + }, + clearHistoryButton: { + label: 'Despejar el historial de impresión' + }, + printResults: { + progressBar: { + label: 'Creación de impresión' + }, + errorMessage: 'Error, inténtalo de nuevo' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Print/nls/fr/resource.js b/viewer/js/gis/dijit/Print/nls/fr/resource.js new file mode 100644 index 000000000..a232434bb --- /dev/null +++ b/viewer/js/gis/dijit/Print/nls/fr/resource.js @@ -0,0 +1,39 @@ +define ({ + title: 'Titre', + format: 'Format', + layout: 'Disposition', + settings: 'Paramètres', + mapScaleExtent: 'Échelle/étendue de la carte', + preserve: 'Préserver', + mapScale: 'échelle de la carte', + mapExtent: 'étendue de la carte', + fullLayoutOptions: 'Options complètes de mise en page', + scaleBarUnits: 'Unités de la barre d\'échelle', + miles: 'Miles', + kilometers: 'Kilomètres', + meters: 'Mètres', + feet: 'Pieds', + includeLegend: 'Inclure la légende', + printQualityOptions: 'Qualité d`impression', + dpiInput: { + label: 'DPI', + invalidMessage: 'S\'il vous plaît entrer une valeur numérique.', + rangeMessage: 'S\'il vous plaît entrer une valeur entre 100 et 300.' + }, + mapOnlyOptions: 'Options MAP_ONLY', + width: 'Largeur', + height: 'Hauteur', + printButton: { + busyLabel: 'Impression', + label: 'Imprimer' + }, + clearHistoryButton: { + label: 'Effacer l\'historique d\'impression' + }, + printResults: { + progressBar: { + label: 'Création de l\'impression' + }, + errorMessage: 'Erreur, réessayez' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Print/nls/pt-br/resource.js b/viewer/js/gis/dijit/Print/nls/pt-br/resource.js new file mode 100644 index 000000000..dbb30c663 --- /dev/null +++ b/viewer/js/gis/dijit/Print/nls/pt-br/resource.js @@ -0,0 +1,40 @@ +// http://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html +define({ + title: 'Título', + format: 'Formato', + layout: 'Modelo', + settings: 'Configurações', + mapScaleExtent: 'Escala/Extensão do Mapa', + preserve: 'Preservar', + mapScale: 'Escala do mapa', + mapExtent: 'Extensão do mapa', + fullLayoutOptions: 'Opções de Modelo Completa', + scaleBarUnits: 'Unidades da barra de escala', + miles: 'Milhas', + kilometers: 'Quilômetros', + meters: 'Metros', + feet: 'Pés', + includeLegend: 'Incluir Legenda', + printQualityOptions: 'Opções da qualidade de Impressão', + dpiInput: { + label: 'DPI', + invalidMessage: 'Por favor entre um valor numérico.', + rangeMessage: 'Por favor entre um valor entre 100 e 300.' + }, + mapOnlyOptions: 'opções MAP_ONLY', + width: 'Largura', + height: 'Altura', + printButton: { + busyLabel: 'imprimindo', + label: 'Imprimir' + }, + clearHistoryButton: { + label: 'Limpar histórico de impressão' + }, + printResults: { + progressBar: { + label: 'Criando impressão' + }, + errorMessage: 'Erro, tente novamente' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Print/nls/pt-pt/resource.js b/viewer/js/gis/dijit/Print/nls/pt-pt/resource.js new file mode 100644 index 000000000..2f9ac62fa --- /dev/null +++ b/viewer/js/gis/dijit/Print/nls/pt-pt/resource.js @@ -0,0 +1,40 @@ +// http://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html +define({ + title: 'Título', + format: 'Formato', + layout: 'Modelo', + settings: 'Configurações', + mapScaleExtent: 'Escala/Extensão do mapa', + preserve: 'Preservar', + mapScale: 'Escala do mapa', + mapExtent: 'Extensão do mapa', + fullLayoutOptions: 'Todas as opções do modelo', + scaleBarUnits: 'Unidades da escala gráfica', + miles: 'Milhas', + kilometers: 'Quilómetros', + meters: 'Metros', + feet: 'Pés', + includeLegend: 'Incluir legenda', + printQualityOptions: 'Opções da qualidade de impressão', + dpiInput: { + label: 'DPI', + invalidMessage: 'Por favor introduza um valor numérico.', + rangeMessage: 'Por favor introduza um valor entre 100 e 300.' + }, + mapOnlyOptions: 'Opções do mapa', + width: 'Largura', + height: 'Altura', + printButton: { + busyLabel: 'a imprimir', + label: 'Imprimir' + }, + clearHistoryButton: { + label: 'Limpar o histórico de impressão' + }, + printResults: { + progressBar: { + label: 'A criar a impressão' + }, + errorMessage: 'Erro, tente novamente' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/Print/nls/resource.js b/viewer/js/gis/dijit/Print/nls/resource.js index 3c250c54d..3af6b5a74 100644 --- a/viewer/js/gis/dijit/Print/nls/resource.js +++ b/viewer/js/gis/dijit/Print/nls/resource.js @@ -1,4 +1,4 @@ -// http://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html +// https://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html define({ root: { title: 'Title', @@ -38,6 +38,10 @@ define({ }, errorMessage: 'Error, try again' } - } + }, + 'es': true, + 'fr': true, + 'pt-br': true, + 'pt-pt': true }); diff --git a/viewer/js/gis/dijit/Print/templates/Print.html b/viewer/js/gis/dijit/Print/templates/Print.html index 28d754273..c8ed5cdab 100644 --- a/viewer/js/gis/dijit/Print/templates/Print.html +++ b/viewer/js/gis/dijit/Print/templates/Print.html @@ -42,12 +42,12 @@
- diff --git a/viewer/js/gis/dijit/StreetView.js b/viewer/js/gis/dijit/StreetView.js index de426f265..a9dc90a0f 100644 --- a/viewer/js/gis/dijit/StreetView.js +++ b/viewer/js/gis/dijit/StreetView.js @@ -1,296 +1,311 @@ -/*global google */ -/*jshint unused:true */ define([ - 'dojo/_base/declare', - 'dijit/_WidgetBase', - 'dijit/_TemplatedMixin', - 'dijit/_WidgetsInTemplateMixin', - 'dojo/_base/lang', - 'dojo/aspect', - 'dojo/topic', - 'esri/layers/GraphicsLayer', - 'esri/graphic', - 'esri/renderers/SimpleRenderer', - 'dojo/text!./StreetView/templates/StreetView.html', - 'esri/symbols/PictureMarkerSymbol', - 'dojo/dom-style', - 'esri/geometry/Point', - 'esri/SpatialReference', - 'dijit/MenuItem', - '//cdnjs.cloudflare.com/ajax/libs/proj4js/2.3.3/proj4.js', - 'dojo/i18n!./StreetView/nls/resource', + 'dojo/_base/declare', + 'dijit/_WidgetBase', + 'dijit/_TemplatedMixin', + 'dijit/_WidgetsInTemplateMixin', + 'dojo/_base/lang', + 'dojo/aspect', + 'dojo/topic', + 'esri/layers/GraphicsLayer', + 'esri/graphic', + 'esri/renderers/SimpleRenderer', + 'dojo/text!./StreetView/templates/StreetView.html', + 'esri/symbols/PictureMarkerSymbol', + 'dojo/dom-style', + 'dojo/dom-geometry', + 'esri/geometry/Point', + 'esri/SpatialReference', + 'dijit/MenuItem', + 'proj4js/proj4', + 'dojo/i18n!./StreetView/nls/resource', + 'gis/plugins/Google', + 'dijit/form/ToggleButton', + 'xstyle/css!./StreetView/css/StreetView.css' +], function (declare, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, lang, aspect, topic, GraphicsLayer, Graphic, SimpleRenderer, template, PictureMarkerSymbol, domStyle, domGeom, Point, SpatialReference, MenuItem, proj4, i18n, Google) { + //cache google so + var google; + return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], { + widgetsInTemplate: true, + templateString: template, + i18n: i18n, + mapClickMode: null, - 'dijit/form/Button', - 'xstyle/css!./StreetView/css/StreetView.css', - 'gis/plugins/async!//maps.google.com/maps/api/js?v=3&sensor=false' -], function (declare, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, lang, aspect, topic, GraphicsLayer, Graphic, SimpleRenderer, template, PictureMarkerSymbol, domStyle, Point, SpatialReference, MenuItem, proj4, i18n) { + panoOptions: null, - return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], { - widgetsInTemplate: true, - templateString: template, - i18n: i18n, - mapClickMode: null, + // in case this changes some day + proj4BaseURL: 'https://epsg.io/', - panoOptions: { - addressControlOptions: { - position: google.maps.ControlPosition.TOP_RIGHT - }, - linksControl: false, - panControl: false, - zoomControlOptions: { - style: google.maps.ZoomControlStyle.SMALL - }, - enableCloseButton: false - }, + // options are ESRI, EPSG and SR-ORG + // See http://sepsg.io/ for more information + proj4Catalog: 'EPSG', - // in case this changes some day - proj4BaseURL: 'http://spatialreference.org/', + // if desired, you can load a projection file from your server + // instead of using one from epsg.io + // i.e., http://server/projections/102642.js + proj4CustomURL: null, - // options are ESRI, EPSG and SR-ORG - // See http://spatialreference.org/ for more information - proj4Catalog: 'EPSG', + postCreate: function () { + this.inherited(arguments); + //load the google api asynchronously + Google.load(lang.hitch(this, function (g) { + //store a reference to google + google = g; - // if desired, you can load a projection file from your server - // instead of using one from spatialreference.org - // i.e., http://server/projections/102642.js - projCustomURL: null, + //init our panoOptions since they depend on google + this.panoOptions = { + addressControlOptions: { + position: google.maps.ControlPosition.TOP_RIGHT + }, + linksControl: false, + panControl: false, + zoomControlOptions: { + style: google.maps.ZoomControlStyle.SMALL + }, + enableCloseButton: false + }; + this.createGraphicsLayer(); + this.map.on('click', lang.hitch(this, 'getStreetView')); - postCreate: function () { - this.inherited(arguments); - this.createGraphicsLayer(); - this.map.on('click', lang.hitch(this, 'getStreetView')); + this.own(topic.subscribe('mapClickMode/currentSet', lang.hitch(this, 'setMapClickMode'))); - this.own(topic.subscribe('mapClickMode/currentSet', lang.hitch(this, 'setMapClickMode'))); + if (this.parentWidget) { + if (this.parentWidget.toggleable) { + this.own(aspect.after(this.parentWidget, 'toggle', lang.hitch(this, function () { + this.onLayoutChange(this.parentWidget.open); + }))); + } + this.own(aspect.after(this.parentWidget, 'resize', lang.hitch(this, 'resize'))); + this.own(topic.subscribe(this.parentWidget.id + '/resize/resize', lang.hitch(this, 'resize'))); + } - if (this.parentWidget) { - if (this.parentWidget.toggleable) { - this.own(aspect.after(this.parentWidget, 'toggle', lang.hitch(this, function () { - this.onLayoutChange(this.parentWidget.open); - }))); - } - this.own(aspect.after(this.parentWidget, 'resize', lang.hitch(this, function () { - if (this.panorama) { - google.maps.event.trigger(this.panorama, 'resize'); - } - }))); - } + if (!window.proj4) { + window.proj4 = proj4; + } - // spatialreference.org uses the old - // Proj4js style so we need an alias - // https://github.com/proj4js/proj4js/issues/23 - window.Proj4js = proj4; + if (this.mapRightClickMenu) { + this.addRightClickMenu(); + } + })); + }, + createGraphicsLayer: function () { + this.pointSymbol = new PictureMarkerSymbol(require.toUrl('gis/dijit/StreetView/images/blueArrow.png'), 30, 30); + this.pointGraphics = new GraphicsLayer({ + id: 'streetview_graphics', + title: 'Street View' + }); + this.pointRenderer = new SimpleRenderer(this.pointSymbol); + this.pointRenderer.label = 'Street View'; + this.pointRenderer.description = 'Street View'; + this.pointGraphics.setRenderer(this.pointRenderer); + this.map.addLayer(this.pointGraphics); + }, + addRightClickMenu: function () { + this.map.on('MouseDown', lang.hitch(this, function (evt) { + this.mapRightClickPoint = evt.mapPoint; + })); + this.mapRightClickMenu.addChild(new MenuItem({ + label: this.i18n.rightClickMenuItem.label, + onClick: lang.hitch(this, 'streetViewFromMapRightClick') + })); + }, + onOpen: function () { + this.pointGraphics.show(); + if (!this.panorama || !this.panoramaService) { + this.panorama = new google.maps.StreetViewPanorama(this.panoNode, this.panoOptions); + this.panoramaService = new google.maps.StreetViewService(); + } + }, + onClose: function () { + // end streetview on close of title pane + this.pointGraphics.hide(); + if (this.mapClickMode === 'streetview') { + this.connectMapClick(); + } + }, + onLayoutChange: function (open) { + if (open) { + this.onOpen(); + } else { + this.onClose(); + } + }, + placePoint: function () { + if (this.streetViewButtonDijit.get('checked')) { + this.disconnectMapClick(); + } else { + this.connectMapClick(); + } + //get map click, set up listener in post create + }, + disconnectMapClick: function () { + this.streetViewButtonDijit.set('checked', true); + this.map.setMapCursor('crosshair'); + topic.publish('mapClickMode/setCurrent', 'streetview'); + }, + connectMapClick: function () { + this.streetViewButtonDijit.set('checked', false); + this.map.setMapCursor('auto'); + topic.publish('mapClickMode/setDefault'); + }, + clearGraphics: function () { + this.pointGraphics.clear(); + domStyle.set(this.noStreetViewResults, 'display', 'block'); + }, + enableStreetViewClick: function () { + this.disconnectMapClick(); + }, + disableStreetViewClick: function () { + this.connectMapClick(); + }, + getStreetView: function (evt, overRide) { + if (this.mapClickMode === 'streetview' || overRide) { + var mapPoint = evt.mapPoint; + if (!mapPoint) { + return; + } - if (this.mapRightClickMenu) { - this.addRightClickMenu(); - } - }, - createGraphicsLayer: function () { - this.pointSymbol = new PictureMarkerSymbol(require.toUrl('gis/dijit/StreetView/images/blueArrow.png'), 30, 30); - this.pointGraphics = new GraphicsLayer({ - id: 'streetview_graphics', - title: 'Street View' - }); - this.pointRenderer = new SimpleRenderer(this.pointSymbol); - this.pointRenderer.label = 'Street View'; - this.pointRenderer.description = 'Street View'; - this.pointGraphics.setRenderer(this.pointRenderer); - this.map.addLayer(this.pointGraphics); - }, - addRightClickMenu: function () { - this.map.on('MouseDown', lang.hitch(this, function (evt) { - this.mapRightClickPoint = evt.mapPoint; - })); - this.mapRightClickMenu.addChild(new MenuItem({ - label: this.i18n.rightClickMenuItem.label, - onClick: lang.hitch(this, 'streetViewFromMapRightClick') - })); - }, - onOpen: function () { - this.pointGraphics.show(); - if (!this.panorama || !this.panoramaService) { - this.panorama = new google.maps.StreetViewPanorama(this.panoNode, this.panoOptions); - this.panoramaService = new google.maps.StreetViewService(); - } - if (this.panorama) { - google.maps.event.trigger(this.panorama, 'resize'); - } - }, - onClose: function () { - // end streetview on close of title pane - this.pointGraphics.hide(); - if (this.mapClickMode === 'streetview') { - this.connectMapClick(); - } - }, - onLayoutChange: function (open) { - if (open) { - this.onOpen(); - } else { - this.onClose(); - } - }, - placePoint: function () { - this.disconnectMapClick(); - //get map click, set up listener in post create - }, - disconnectMapClick: function () { - this.map.setMapCursor('crosshair'); - topic.publish('mapClickMode/setCurrent', 'streetview'); - }, - connectMapClick: function () { - this.map.setMapCursor('auto'); - topic.publish('mapClickMode/setDefault'); - }, - clearGraphics: function () { - this.pointGraphics.clear(); - domStyle.set(this.noStreetViewResults, 'display', 'block'); - }, - enableStreetViewClick: function () { - this.disconnectMapClick(); - }, - disableStreetViewClick: function () { - this.connectMapClick(); - }, - getStreetView: function (evt, overRide) { - if (this.mapClickMode === 'streetview' || overRide) { - var mapPoint = evt.mapPoint; - if (!mapPoint) { - return; - } + if (this.parentWidget && !this.parentWidget.open) { + this.parentWidget.toggle(); + } - if (this.parentWidget && !this.parentWidget.open) { - this.parentWidget.toggle(); - } + // convert the map point's coordinate system into lat/long + var geometry = null, + wkid = mapPoint.spatialReference.wkid; + if (wkid === 102100) { + wkid = 3857; + } + var key = this.proj4Catalog + ':' + String(wkid); + if (!proj4.defs[key]) { + var url = this.proj4CustomURL || this.proj4BaseURL + String(wkid) + '.js'; + require([url], lang.hitch(this, 'getStreetView', evt, true)); + return; + } + // only need one projection as we are + // converting to WGS84 lat/long + var projPoint = proj4(proj4.defs[key]).inverse([mapPoint.x, mapPoint.y]); + if (projPoint) { + geometry = { + x: projPoint[0], + y: projPoint[1] + }; + } - // convert the map point's coordinate system into lat/long - var geometry = null, - wkid = mapPoint.spatialReference.wkid; - if (wkid === 102100) { - wkid = 3857; - } - var key = this.proj4Catalog + ':' + wkid; - if (!proj4.defs[key]) { - var url = this.proj4CustomURL || this.proj4BaseURL + 'ref/' + this.proj4Catalog.toLowerCase() + '/' + wkid + '/proj4js/'; - require([url], lang.hitch(this, 'getStreetView', evt, true)); - return; - } - // only need one projection as we are - // converting to WGS84 lat/long - var projPoint = proj4(proj4.defs[key]).inverse([mapPoint.x, mapPoint.y]); - if (projPoint) { - geometry = { - x: projPoint[0], - y: projPoint[1] - }; - } + domStyle.set(this.streetViewInstructions, 'display', 'none'); + if (geometry) { + domStyle.set(this.noStreetViewResults, 'display', 'none'); + this.getPanoramaLocation(geometry); + } else { + this.setPanoPlace = null; + this.clearGraphics(); + domStyle.set(this.noStreetViewResults, 'display', 'block'); + } + } - if (geometry) { - domStyle.set(this.noStreetViewResults, 'display', 'none'); - domStyle.set(this.loadingStreetView, 'display', 'inline-block'); - this.getPanoramaLocation(geometry); - } else { - this.setPanoPlace = null; - this.clearGraphics(); - domStyle.set(this.noStreetViewResults, 'display', 'block'); - } - } + }, + getPanoramaLocation: function (geoPoint) { + var place = new google.maps.LatLng(geoPoint.y, geoPoint.x); + this.panoramaService.getPanoramaByLocation(place, 50, lang.hitch(this, 'getPanoramaByLocationComplete', geoPoint)); + // Panorama Events -- Changed location + google.maps.event.addListener(this.panorama, 'position_changed', lang.hitch(this, 'setPlaceMarkerPosition')); + // Panorama Events -- Changed Rotation + google.maps.event.addListener(this.panorama, 'pov_changed', lang.hitch(this, 'setPlaceMarkerRotation')); + }, + getPanoramaByLocationComplete: function (geoPoint, StreetViewPanoramaData, StreetViewStatus) { + if (StreetViewStatus === 'OK') { + this.disableStreetViewClick(); + var place = new google.maps.LatLng(geoPoint.y, geoPoint.x); + this.setPanoPlace = place; + this.firstSet = true; + this.panorama.setPosition(place); + } else if (StreetViewStatus === 'ZERO_RESULTS') { + this.setPanoPlace = null; + this.clearGraphics(); + // reset default map click mode + this.connectMapClick(); + domStyle.set(this.noStreetViewResults, 'display', 'block'); + } else { + this.setPanoPlace = null; + this.clearGraphics(); + topic.publish('viewer/handleError', { + source: 'StreetView', + error: 'Unknown.' + }); + } + }, + resize: function (options) { + if (options && options.h) { + domGeom.setContentSize(this.containerNode, { + h: (options.h - 2) + }); + } + if (this.panorama) { + google.maps.event.trigger(this.panorama, 'resize'); + } + }, + setPlaceMarkerPosition: function () { + if (!this.placeMarker || this.pointGraphics.graphics.length === 0) { + this.placeMarker = new Graphic(); + // Add graphic to the map + this.pointGraphics.add(this.placeMarker); + } + // get the new lat/long from streetview + var panoPosition = this.panorama.getPosition(); + var positionLat = panoPosition.lat(); + var positionLong = panoPosition.lng(); + // Make sure they are numbers + if (!isNaN(positionLat) && !isNaN(positionLong)) { + // convert the resulting lat/long to the map's spatial reference + var xy = null, + wkid = this.map.spatialReference.wkid; + if (wkid === 102100) { + wkid = 3857; + } + var key = this.proj4Catalog + ':' + String(wkid); + if (!proj4.defs[key]) { + var url = this.proj4CustomURL || this.proj4BaseURL + String(wkid) + '.js'; + require([url], lang.hitch(this, 'setPlaceMarkerPosition')); + return; + } + // only need the one projection as we are + // converting from WGS84 lat/long + xy = proj4(proj4.defs[key]).forward([positionLong, positionLat]); + if (xy) { + var point = new Point(xy, new SpatialReference({ + wkid: wkid + })); - }, - getPanoramaLocation: function (geoPoint) { - var place = new google.maps.LatLng(geoPoint.y, geoPoint.x); - this.panoramaService.getPanoramaByLocation(place, 50, lang.hitch(this, 'getPanoramaByLocationComplete', geoPoint)); - // Panorama Events -- Changed location - google.maps.event.addListener(this.panorama, 'position_changed', lang.hitch(this, 'setPlaceMarkerPosition')); - // Panorama Events -- Changed Rotation - google.maps.event.addListener(this.panorama, 'pov_changed', lang.hitch(this, 'setPlaceMarkerRotation')); - }, - getPanoramaByLocationComplete: function (geoPoint, StreetViewPanoramaData, StreetViewStatus) { - domStyle.set(this.loadingStreetView, 'display', 'none'); - if (StreetViewStatus === 'OK') { - this.disableStreetViewClick(); - var place = new google.maps.LatLng(geoPoint.y, geoPoint.x); - this.setPanoPlace = place; - this.firstSet = true; - this.panorama.setPosition(place); - } else if (StreetViewStatus === 'ZERO_RESULTS') { - this.setPanoPlace = null; - this.clearGraphics(); - // reset default map click mode - this.connectMapClick(); - domStyle.set(this.noStreetViewResults, 'display', 'block'); - } else { - this.setPanoPlace = null; - this.clearGraphics(); - topic.publish('viewer/handleError', { - source: 'StreetView', - error: 'Unknown.' - }); - } - }, - setPlaceMarkerPosition: function () { - if (!this.placeMarker || this.pointGraphics.graphics.length === 0) { - this.placeMarker = new Graphic(); - // Add graphic to the map - this.pointGraphics.add(this.placeMarker); - } - // get the new lat/long from streetview - var panoPosition = this.panorama.getPosition(); - var positionLat = panoPosition.lat(); - var positionLong = panoPosition.lng(); - // Make sure they are numbers - if (!isNaN(positionLat) && !isNaN(positionLong)) { - // convert the resulting lat/long to the map's spatial reference - var xy = null, - wkid = this.map.spatialReference.wkid; - if (wkid === 102100) { - wkid = 3857; - } - var key = this.proj4Catalog + ':' + wkid; - if (!proj4.defs[key]) { - var url = this.proj4CustomURL || this.proj4BaseURL + 'ref/' + this.proj4Catalog.toLowerCase() + '/' + wkid + '/proj4js/'; - require([url], lang.hitch(this, 'setPlaceMarkerPosition')); - return; - } - // only need the one projection as we are - // converting from WGS84 lat/long - xy = proj4(proj4.defs[key]).forward([positionLong, positionLat]); - if (xy) { - var point = new Point(xy, new SpatialReference({ - wkid: wkid - })); - - // change point position on the map - this.placeMarker.setGeometry(point); - if (this.setPanoPlace && !this.firstSet) { - var heading = google.maps.geometry.spherical.computeHeading(panoPosition, this.setPanoPlace); - this.panorama.setPov({ - heading: heading, - pitch: 0 - }); - setTimeout(lang.hitch(this, function () { - this.setPanoPlace = null; - }), 1000); - } else { - this.firstSet = false; - } - } - } - }, - setPlaceMarkerRotation: function () { - if (this.placeMarker) { - var pov = this.panorama.getPov(); - this.pointSymbol.setAngle(pov.heading); - this.pointGraphics.refresh(); - } - }, - streetViewFromMapRightClick: function () { - var evt = { - mapPoint: this.mapRightClickPoint - }; - this.getStreetView(evt, true); - }, - setMapClickMode: function (mode) { - this.mapClickMode = mode; - } - }); -}); \ No newline at end of file + // change point position on the map + this.placeMarker.setGeometry(point); + if (this.setPanoPlace && !this.firstSet) { + var heading = google.maps.geometry.spherical.computeHeading(panoPosition, this.setPanoPlace); + this.panorama.setPov({ + heading: heading, + pitch: 0 + }); + setTimeout(lang.hitch(this, function () { + this.setPanoPlace = null; + }), 1000); + } else { + this.firstSet = false; + } + } + } + }, + setPlaceMarkerRotation: function () { + if (this.placeMarker) { + var pov = this.panorama.getPov(); + this.pointSymbol.setAngle(pov.heading); + this.pointGraphics.refresh(); + } + }, + streetViewFromMapRightClick: function () { + var evt = { + mapPoint: this.mapRightClickPoint + }; + this.getStreetView(evt, true); + }, + setMapClickMode: function (mode) { + this.mapClickMode = mode; + } + }); +}); diff --git a/viewer/js/gis/dijit/StreetView/css/StreetView.css b/viewer/js/gis/dijit/StreetView/css/StreetView.css index 1f943023f..d13f67d68 100644 --- a/viewer/js/gis/dijit/StreetView/css/StreetView.css +++ b/viewer/js/gis/dijit/StreetView/css/StreetView.css @@ -1,60 +1,50 @@ .gis_StreetView { - padding: 5px; + width: 100%; + height: 250px; + padding-bottom: 5px; + position: relative; } -.gis_StreetView .buttonActionBar { - padding: 3px 0px 2px 0px; - text-align: right; - width: 100%; +.gis_StreetView .streetViewButton { + position: absolute; + left: 4px; + top: 4px; + z-index: 9; } -.gis_StreetView .buttonActionBar .loadingStreetView { - display: none; - width: 18px; - position: relative; - top: 5px; - margin-right: 10px; - background-image: url('../images/loading.gif'); +.gis_StreetView .streetViewButton .dijitButtonNode { + padding: 6px; } -.gis_StreetView .streetViewNode { - border: 1px solid #999999; +.gis_StreetView .streetViewPano { + border: 1px solid #CCC; width: 100%; - height: 275px; + height: 100%; } -.floatingWidget .gis_StreetView .streetViewNode { +.floatingWidget .gis_StreetView .streetViewPano { width: 400px; height: 275px; } -.gis_StreetView .pegmanIcon { - background-image: url(../images/googleIcon.png); - background-size: contain; - background-repeat: no-repeat; - width: 16px; - height: 20px; - vertical-align: middle; - margin-top: -4px; - margin-bottom: -4px; -} - +.gis_StreetView .streetViewInstructions, .gis_StreetView .noStreetViewResults { - display: none; background-color: black; width: 100%; height: 100%; z-index: 2; - position: relative; + position: absolute; +} +.gis_StreetView .noStreetViewResults { + display: none; } +.gis_StreetView .streetViewInstructionsText, .gis_StreetView .noStreetViewResultsText { - color: white; background-color: black; + color: white; z-index: 2; - position: relative; - top: 40%; - text-align: center; - font-size: 12pt; + position: absolute; + top: 50px; padding: 10px; } \ No newline at end of file diff --git a/viewer/js/gis/dijit/StreetView/images/googleIcon.png b/viewer/js/gis/dijit/StreetView/images/googleIcon.png deleted file mode 100644 index c0984aae5..000000000 Binary files a/viewer/js/gis/dijit/StreetView/images/googleIcon.png and /dev/null differ diff --git a/viewer/js/gis/dijit/StreetView/images/loading.gif b/viewer/js/gis/dijit/StreetView/images/loading.gif deleted file mode 100644 index 5bb90fd6a..000000000 Binary files a/viewer/js/gis/dijit/StreetView/images/loading.gif and /dev/null differ diff --git a/viewer/js/gis/dijit/StreetView/images/svicon.png b/viewer/js/gis/dijit/StreetView/images/svicon.png deleted file mode 100644 index 914d5c8ba..000000000 Binary files a/viewer/js/gis/dijit/StreetView/images/svicon.png and /dev/null differ diff --git a/viewer/js/gis/dijit/StreetView/nls/es/resource.js b/viewer/js/gis/dijit/StreetView/nls/es/resource.js new file mode 100644 index 000000000..2318abc5e --- /dev/null +++ b/viewer/js/gis/dijit/StreetView/nls/es/resource.js @@ -0,0 +1,9 @@ +define ({ + messages: { + instructions: 'Haga clic en el botón de StreetView a continuación, haga clic en el mapa en su posición deseada.', + notAvailable: 'Desafortunadamente, Google StreetView todavía no está disponible en ese lugar.' + }, + rightClickMenuItem: { + label: 'Google StreetView aquí' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/StreetView/nls/fr/resource.js b/viewer/js/gis/dijit/StreetView/nls/fr/resource.js new file mode 100644 index 000000000..f3c961b39 --- /dev/null +++ b/viewer/js/gis/dijit/StreetView/nls/fr/resource.js @@ -0,0 +1,9 @@ +define ({ + messages: { + instructions: 'Cliquez sur le bouton StreetView puis cliquez sur la carte à l\'endroit désiré.', + notAvailable: 'Malheureusement, les images de Google StreetView ne sont pas encore disponible à cet endroit.' + }, + rightClickMenuItem: { + label: 'Ouvrir Google StreetView à cet endroit' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/StreetView/nls/pt-br/resource.js b/viewer/js/gis/dijit/StreetView/nls/pt-br/resource.js new file mode 100644 index 000000000..6e9f7e049 --- /dev/null +++ b/viewer/js/gis/dijit/StreetView/nls/pt-br/resource.js @@ -0,0 +1,10 @@ +// http://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html +define({ + messages: { + instructions: 'Clique no botão do StreetView e depois clique na localização desejada no mapa.', + notAvailable: 'Infelizmente, o Google Street View não está disponível nesta localização.' + }, + rightClickMenuItem: { + label: 'Street View aqui' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/StreetView/nls/pt-pt/resource.js b/viewer/js/gis/dijit/StreetView/nls/pt-pt/resource.js new file mode 100644 index 000000000..6e9f7e049 --- /dev/null +++ b/viewer/js/gis/dijit/StreetView/nls/pt-pt/resource.js @@ -0,0 +1,10 @@ +// http://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html +define({ + messages: { + instructions: 'Clique no botão do StreetView e depois clique na localização desejada no mapa.', + notAvailable: 'Infelizmente, o Google Street View não está disponível nesta localização.' + }, + rightClickMenuItem: { + label: 'Street View aqui' + } +}); \ No newline at end of file diff --git a/viewer/js/gis/dijit/StreetView/nls/resource.js b/viewer/js/gis/dijit/StreetView/nls/resource.js index 8dbb2fa92..6e80605ca 100644 --- a/viewer/js/gis/dijit/StreetView/nls/resource.js +++ b/viewer/js/gis/dijit/StreetView/nls/resource.js @@ -1,15 +1,17 @@ -// http://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html +// https://dojotoolkit.org/reference-guide/1.10/dojo/i18n.html define({ root: { - activateButton: { - label: 'Activate with map click' - }, messages: { - notAvailable: 'Street View not available at this location.' + instructions: 'Click the StreetView button then click the map at your desired location.', + notAvailable: 'Unfortunately, Google StreetView imagery is not yet available at that location.' }, rightClickMenuItem: { - label: 'Street View here' + label: 'Google StreetView here' } - } + }, + 'es': true, + 'fr': true, + 'pt-br': true, + 'pt-pt': true }); diff --git a/viewer/js/gis/dijit/StreetView/templates/StreetView.html b/viewer/js/gis/dijit/StreetView/templates/StreetView.html index 108785294..30ba826b6 100644 --- a/viewer/js/gis/dijit/StreetView/templates/StreetView.html +++ b/viewer/js/gis/dijit/StreetView/templates/StreetView.html @@ -1,15 +1,15 @@ -
-
+
+
+ + +
+ ${i18n.messages.instructions} +
+
${i18n.messages.notAvailable}
-
- - -
diff --git a/viewer/js/gis/dijit/Vim.js b/viewer/js/gis/dijit/Vim.js index 3c55acffa..22988ed98 100644 --- a/viewer/js/gis/dijit/Vim.js +++ b/viewer/js/gis/dijit/Vim.js @@ -2,54 +2,57 @@ // Used to serialize/deserialize the identitymanager storing // credential objects (tokens) in either local storage or a cookie // usage: -// param 1: the name of the cookie/localstorage key -// new Vim(idStateName); +// param 1: the name of the cookie/localstorage key +// new Vim(idStateName); define([ - 'dojo/_base/declare', - 'esri/kernel', - 'dojo/cookie', - 'dojo/json', - 'dojo/_base/unload', - 'dojo/_base/lang' -], function(declare, kernel, cookie, JSON, baseUnload, lang) { - return declare(null, { - constructor: function(idStateName) { - this.idStateName = idStateName || 'esri_jsapi_id_manager_data'; - baseUnload.addOnUnload(lang.hitch(this, 'storeCredentials')); - this.loadCredentials(); - }, - loadCredentials: function() { - var idJson, idObject; - if (this._supportsLocalStorage()) { - idJson = window.localStorage.getItem(this.idStateName); - } else { - idJson = cookie(this.idStateName); - } - if (idJson && idJson != 'null' && idJson.length > 4) { - idObject = JSON.parse(idJson); - kernel.id.initialize(idObject); - } - }, - storeCredentials: function() { - if (kernel.id.credentials.length === 0) { - return; - } - var idString = JSON.stringify(kernel.id.toJson()); - if (this._supportsLocalStorage()) { - window.localStorage.setItem(this.idStateName, idString); - } else { - cookie(this.idStateName, idString, { - expires: 1 - }); - } - }, - _supportsLocalStorage: function() { - try { - return 'localStorage' in window && window.localStorage !== null; - } catch (e) { - return false; - } - } - }); + 'dojo/_base/declare', + 'esri/kernel', + 'dojo/cookie', + 'dojo/json', + 'dojo/_base/unload', + 'dojo/_base/lang' +], function (declare, kernel, cookie, JSON, baseUnload, lang) { + + return declare(null, { + constructor: function (idStateName) { + this.idStateName = idStateName || 'esri_jsapi_id_manager_data'; + baseUnload.addOnUnload(lang.hitch(this, 'storeCredentials')); + this.loadCredentials(); + }, + loadCredentials: function () { + var idJson, idObject; + if (this._supportsLocalStorage()) { + idJson = window.localStorage.getItem(this.idStateName); + } else { + idJson = cookie(this.idStateName); + } + if (idJson && idJson !== 'null' && idJson.length > 4) { + idObject = JSON.parse(idJson); + kernel.id.initialize(idObject); + } + }, + + storeCredentials: function () { + if (kernel.id.credentials.length === 0) { + return; + } + var idString = JSON.stringify(kernel.id.toJson()); + if (this._supportsLocalStorage()) { + window.localStorage.setItem(this.idStateName, idString); + } else { + cookie(this.idStateName, idString, { + expires: 1 + }); + } + }, + + _supportsLocalStorage: function () { + try { + return 'localStorage' in window && window.localStorage !== null; + } catch (e) { + return false; + } + } + }); }); diff --git a/viewer/js/gis/dijit/_FloatingWidgetMixin.js b/viewer/js/gis/dijit/_FloatingWidgetMixin.js index 23e35706d..c3dc7f5d6 100644 --- a/viewer/js/gis/dijit/_FloatingWidgetMixin.js +++ b/viewer/js/gis/dijit/_FloatingWidgetMixin.js @@ -1,22 +1,23 @@ define([ - 'dojo/_base/declare', - 'dojo/on', - 'dojo/_base/lang' + 'dojo/_base/declare', + 'dojo/on', + 'dojo/_base/lang' ], function (declare, on, lang) { - return declare(null, { - startup: function () { - // var parentWidget = this.getParent(); - if (this.parentWidget && this.parentWidget.declaredClass === 'gis.dijit.FloatingWidget' && this.onOpen) { - on(this.parentWidget, 'show', lang.hitch(this, 'onOpen')); - } - if (this.parentWidget && this.parentWidget.declaredClass === 'gis.dijit.FloatingWidget' && this.onClose) { - on(this.parentWidget, 'hide', lang.hitch(this, 'onClose')); - } - if (this.parentWidget && this.parentWidget.declaredClass === 'gis.dijit.FloatingWidget' && this.openOnStartup) { - this.parentWidget.show(); - } - this.inherited(arguments); - } - }); + return declare(null, { + startup: function () { + // var parentWidget = this.getParent(); + if (this.parentWidget && this.parentWidget.declaredClass === 'gis.dijit.FloatingWidget' && this.onOpen) { + on(this.parentWidget, 'show', lang.hitch(this, 'onOpen')); + } + if (this.parentWidget && this.parentWidget.declaredClass === 'gis.dijit.FloatingWidget' && this.onClose) { + on(this.parentWidget, 'hide', lang.hitch(this, 'onClose')); + } + if (this.parentWidget && this.parentWidget.declaredClass === 'gis.dijit.FloatingWidget' && this.openOnStartup) { + this.parentWidget.show(); + } + + this.inherited(arguments); + } + }); }); \ No newline at end of file diff --git a/viewer/js/gis/plugins/Google.js b/viewer/js/gis/plugins/Google.js new file mode 100644 index 000000000..796c6926c --- /dev/null +++ b/viewer/js/gis/plugins/Google.js @@ -0,0 +1,223 @@ +//https://www.npmjs.com/package/google-maps +/* eslint-disable */ +(function(root, factory) { + + if (root === null) { + //throw new Error('Google-maps package can be used only in browser'); + } + + if (typeof define === 'function' && define.amd) { + define(factory); + } else if (typeof exports === 'object') { + module.exports = factory(); + } else { + root.GoogleMapsLoader = factory(); + } + +})(typeof window !== 'undefined' ? window : null, function() { + + + 'use strict'; + + + var script = null; + + var google = null; + + var loading = false; + + var callbacks = []; + + var onLoadEvents = []; + + var originalCreateLoaderMethod = null; + + + var GoogleMapsLoader = {}; + + + GoogleMapsLoader.URL = 'https://maps.googleapis.com/maps/api/js'; + + GoogleMapsLoader.KEY = null; + + GoogleMapsLoader.LIBRARIES = []; + + GoogleMapsLoader.CLIENT = null; + + GoogleMapsLoader.CHANNEL = null; + + GoogleMapsLoader.LANGUAGE = null; + + GoogleMapsLoader.REGION = null; + + GoogleMapsLoader.VERSION = '3'; + + GoogleMapsLoader.WINDOW_CALLBACK_NAME = '__google_maps_api_provider_initializator__'; + + + GoogleMapsLoader._googleMockApiObject = {}; + + + GoogleMapsLoader.load = function(fn) { + if (google === null) { + if (loading === true) { + if (fn) { + callbacks.push(fn); + } + } else { + loading = true; + + window[GoogleMapsLoader.WINDOW_CALLBACK_NAME] = function() { + ready(fn); + }; + + GoogleMapsLoader.createLoader(); + } + } else if (fn) { + fn(google); + } + }; + + + GoogleMapsLoader.createLoader = function() { + script = document.createElement('script'); + script.type = 'text/javascript'; + script.src = GoogleMapsLoader.createUrl(); + + document.body.appendChild(script); + }; + + + GoogleMapsLoader.isLoaded = function() { + return google !== null; + }; + + + GoogleMapsLoader.createUrl = function() { + var url = GoogleMapsLoader.URL; + + url += '?callback=' + GoogleMapsLoader.WINDOW_CALLBACK_NAME; + + if (GoogleMapsLoader.KEY) { + url += '&key=' + GoogleMapsLoader.KEY; + } + + if (GoogleMapsLoader.LIBRARIES.length > 0) { + url += '&libraries=' + GoogleMapsLoader.LIBRARIES.join(','); + } + + if (GoogleMapsLoader.VERSION) { + url += '&v=' + GoogleMapsLoader.VERSION; + } + + if (GoogleMapsLoader.CLIENT) { + url += '&client=' + GoogleMapsLoader.CLIENT; + } + + if (GoogleMapsLoader.CHANNEL) { + url += '&channel=' + GoogleMapsLoader.CHANNEL; + } + + if (GoogleMapsLoader.LANGUAGE) { + url += '&language=' + GoogleMapsLoader.LANGUAGE; + } + + if (GoogleMapsLoader.REGION) { + url += '®ion=' + GoogleMapsLoader.REGION; + } + + return url; + }; + + + GoogleMapsLoader.release = function(fn) { + var release = function() { + GoogleMapsLoader.KEY = null; + GoogleMapsLoader.LIBRARIES = []; + GoogleMapsLoader.CLIENT = null; + GoogleMapsLoader.CHANNEL = null; + GoogleMapsLoader.LANGUAGE = null; + GoogleMapsLoader.REGION = null; + GoogleMapsLoader.VERSION = googleVersion; + + google = null; + loading = false; + callbacks = []; + onLoadEvents = []; + + if (typeof window.google !== 'undefined') { + delete window.google; + } + + if (typeof window[GoogleMapsLoader.WINDOW_CALLBACK_NAME] !== 'undefined') { + delete window[GoogleMapsLoader.WINDOW_CALLBACK_NAME]; + } + + if (originalCreateLoaderMethod !== null) { + GoogleMapsLoader.createLoader = originalCreateLoaderMethod; + originalCreateLoaderMethod = null; + } + + if (script !== null) { + script.parentElement.removeChild(script); + script = null; + } + + if (fn) { + fn(); + } + }; + + if (loading) { + GoogleMapsLoader.load(function() { + release(); + }); + } else { + release(); + } + }; + + + GoogleMapsLoader.onLoad = function(fn) { + onLoadEvents.push(fn); + }; + + + GoogleMapsLoader.makeMock = function() { + originalCreateLoaderMethod = GoogleMapsLoader.createLoader; + + GoogleMapsLoader.createLoader = function() { + window.google = GoogleMapsLoader._googleMockApiObject; + window[GoogleMapsLoader.WINDOW_CALLBACK_NAME](); + }; + }; + + + var ready = function(fn) { + var i; + + loading = false; + + if (google === null) { + google = window.google; + } + + for (i = 0; i < onLoadEvents.length; i++) { + onLoadEvents[i](google); + } + + if (fn) { + fn(google); + } + + for (i = 0; i < callbacks.length; i++) { + callbacks[i](google); + } + + callbacks = []; + }; + + + return GoogleMapsLoader; + +}); diff --git a/viewer/js/gis/plugins/async.js b/viewer/js/gis/plugins/async.js index 97d8f22fc..bf56f173d 100644 --- a/viewer/js/gis/plugins/async.js +++ b/viewer/js/gis/plugins/async.js @@ -1,14 +1,13 @@ -/*global dojoConfig */ -/*jshint unused:true */ define(function () { + var cb = '_asyncApiLoaderCallback'; return { load: function (param, req, loadCallback) { if (!cb) { return; } else { - dojoConfig[cb] = function () { - delete dojoConfig[cb]; + window.dojoConfig[cb] = function () { + delete window.dojoConfig[cb]; cb = null; loadCallback(); }; diff --git a/viewer/js/viewer/Controller.js b/viewer/js/viewer/Controller.js deleted file mode 100644 index 0073c6967..000000000 --- a/viewer/js/viewer/Controller.js +++ /dev/null @@ -1,573 +0,0 @@ -define([ - 'esri/map', - 'dojo/dom', - 'dojo/dom-style', - 'dojo/dom-geometry', - 'dojo/dom-class', - 'dojo/on', - 'dojo/_base/array', - 'dijit/layout/BorderContainer', - 'dijit/layout/ContentPane', - 'gis/dijit/FloatingTitlePane', - 'dojo/_base/lang', - 'dojo/text!./templates/mapOverlay.html', - 'gis/dijit/FloatingWidgetDialog', - 'put-selector', - 'dojo/aspect', - 'dojo/has', - 'dojo/topic', - 'esri/dijit/PopupMobile', - 'dijit/Menu', - 'esri/IdentityManager' -], function (Map, dom, domStyle, domGeom, domClass, on, array, BorderContainer, ContentPane, FloatingTitlePane, lang, mapOverlay, FloatingWidgetDialog, put, aspect, has, topic, PopupMobile, Menu) { - - return { - legendLayerInfos: [], - editorLayerInfos: [], - identifyLayerInfos: [], - layerControlLayerInfos: [], - panes: { - left: { - id: 'sidebarLeft', - placeAt: 'outer', - collapsible: true, - region: 'left' - }, - center: { - id: 'mapCenter', - placeAt: 'outer', - region: 'center', - content: mapOverlay - } - }, - collapseButtons: {}, - startup: function (config) { - this.config = config; - this.mapClickMode = { - current: config.defaultMapClickMode, - defaultMode: config.defaultMapClickMode - }; - // simple feature detection. kinda like dojox/mobile without the overhead - if (has('touch') && (has('ios') || has('android') || has('bb'))) { - has.add('mobile', true); - if (screen.availWidth < 500 || screen.availHeight < 500) { - has.add('phone', true); - } else { - has.add('tablet', true); - } - } - if (config.titles) { - this.addTitles(); - } - this.addTopics(); - this.initPanes(); - - if (config.isDebug) { - window.app = this; //dev only - } - }, - // add topics for subscribing and publishing - addTopics: function () { - // toggle a sidebar pane - topic.subscribe('viewer/togglePane', lang.hitch(this, function (args) { - this.togglePane(args.pane, args.show); - })); - - // load a widget - topic.subscribe('viewer/loadWidget', lang.hitch(this, function (args) { - this.widgetLoader(args.options, args.position); - })); - - // setup error handler. centralize the debugging - if (this.config.isDebug) { - topic.subscribe('viewer/handleError', lang.hitch(this, 'handleError')); - } - - // set the current mapClickMode - topic.subscribe('mapClickMode/setCurrent', lang.hitch(this, function (mode) { - this.mapClickMode.current = mode; - topic.publish('mapClickMode/currentSet', mode); - })); - - // set the current mapClickMode to the default mode - topic.subscribe('mapClickMode/setDefault', lang.hitch(this, function () { - topic.publish('mapClickMode/setCurrent', this.mapClickMode.defaultMode); - })); - - }, - // set titles (if any) - addTitles: function () { - var titles = this.config.titles; - if (titles.header) { - var headerTitleNode = dom.byId('headerTitleSpan'); - if (headerTitleNode) { - headerTitleNode.innerHTML = titles.header; - } - } - if (titles.subHeader) { - var subHeaderTitle = dom.byId('subHeaderTitleSpan'); - if (subHeaderTitle) { - subHeaderTitle.innerHTML = titles.subHeader; - } - } - if (titles.pageTitle) { - document.title = titles.pageTitle; - } - }, - // setup all the sidebar panes - initPanes: function () { - var key, panes = this.config.panes || {}; - for (key in this.panes) { - if (this.panes.hasOwnProperty(key)) { - panes[key] = lang.mixin(this.panes[key], panes[key]); - } - } - - this.panes.outer = new BorderContainer({ - id: 'borderContainerOuter', - design: 'sidebar', - gutters: false - }).placeAt(document.body); - - var options, placeAt, type; - for (key in panes) { - if (panes.hasOwnProperty(key)) { - options = lang.clone(panes[key]); - placeAt = this.panes[options.placeAt] || this.panes.outer; - options.id = options.id || key; - type = options.type; - delete options.placeAt; - delete options.type; - delete options.collapsible; - if (placeAt) { - if (type === 'border') { - this.panes[key] = new BorderContainer(options).placeAt(placeAt); - } else if (options.region) { - this.panes[key] = new ContentPane(options).placeAt(placeAt); - } - } - } - } - this.panes.outer.startup(); - this.initMap(); - - // where to place the buttons - // either the center map pane or the outer pane? - this.collapseButtonsPane = this.config.collapseButtonsPane || 'outer'; - - for (key in panes) { - if (panes.hasOwnProperty(key)) { - if (panes[key].collapsible) { - this.collapseButtons[key] = put(this.panes[this.collapseButtonsPane].domNode, 'div.sidebarCollapseButton.sidebar' + key + 'CollapseButton.sidebarCollapseButton' + ((key === 'bottom' || key === 'top') ? 'Vert' : 'Horz') + ' div.dijitIcon.button.close').parentNode; - on(this.collapseButtons[key], 'click', lang.hitch(this, 'togglePane', key)); - this.positionSideBarToggle(key); - if (this.collapseButtonsPane === 'outer') { - var splitter = this.panes[key]._splitterWidget; - if (splitter) { - aspect.after(splitter, '_startDrag', lang.hitch(this, 'splitterStartDrag', key)); - aspect.after(splitter, '_stopDrag', lang.hitch(this, 'splitterStopDrag', key)); - } - } - if (panes[key].open !== undefined) { - this.togglePane(key, panes[key].open); - } - } - if (key !== 'center' && this.panes[key]._splitterWidget) { - domClass.add(this.map.root.parentNode, 'pane' + key); - if (key === 'right' && this.panes.top) { - domClass.add(this.panes.top.domNode, 'pane' + key); - } - if (key === 'right' && this.panes.bottom) { - domClass.add(this.panes.bottom.domNode, 'pane' + key); - } - if (key === 'left' && this.panes.top) { - domClass.add(this.panes.top.domNode, 'pane' + key); - } - if (key === 'left' && this.panes.bottom) { - domClass.add(this.panes.bottom.domNode, 'pane' + key); - } - } - } - } - - // respond to media query changes - // matchMedia works in most browsers (http://caniuse.com/#feat=matchmedia) - if (window.matchMedia) { - window.matchMedia('(max-width: 991px)').addListener(lang.hitch(this, 'repositionSideBarButtons')); - window.matchMedia('(max-width: 767px)').addListener(lang.hitch(this, 'repositionSideBarButtons')); - } - - this.panes.outer.resize(); - }, - initMap: function () { - if (has('phone') && !this.config.mapOptions.infoWindow) { - this.config.mapOptions.infoWindow = new PopupMobile(null, put('div')); - } - this.map = new Map('mapCenter', this.config.mapOptions); - if (this.config.mapOptions.basemap) { - this.map.on('load', lang.hitch(this, 'initLayers')); - } else { - this.initLayers(); - } - if (this.config.operationalLayers && this.config.operationalLayers.length > 0) { - on.once(this.map, 'layers-add-result', lang.hitch(this, 'initWidgets')); - } else { - this.initWidgets(); - } - }, - initLayers: function () { - this.map.on('resize', function (evt) { - var pnt = evt.target.extent.getCenter(); - setTimeout(function () { - evt.target.centerAt(pnt); - }, 100); - }); - - this.layers = []; - var layerTypes = { - csv: 'CSV', - dataadapter: 'DataAdapterFeature', //untested - dynamic: 'ArcGISDynamicMapService', - feature: 'Feature', - georss: 'GeoRSS', - image: 'ArcGISImageService', - imagevector: 'ArcGISImageServiceVector', - kml: 'KML', - label: 'Label', //untested - mapimage: 'MapImage', //untested - osm: 'OpenStreetMap', - raster: 'Raster', - stream: 'Stream', - tiled: 'ArcGISTiledMapService', - webtiled: 'WebTiled', - wms: 'WMS', - wmts: 'WMTS' //untested - }; - // loading all the required modules first ensures the layer order is maintained - var modules = []; - array.forEach(this.config.operationalLayers, function (layer) { - var type = layerTypes[layer.type]; - if (type) { - modules.push('esri/layers/' + type + 'Layer'); - } else { - this.handleError({ - source: 'Controller', - error: 'Layer type "' + layer.type + '"" isnot supported: ' - }); - } - }, this); - require(modules, lang.hitch(this, function () { - array.forEach(this.config.operationalLayers, function (layer) { - var type = layerTypes[layer.type]; - if (type) { - require(['esri/layers/' + type + 'Layer'], lang.hitch(this, 'initLayer', layer)); - } - }, this); - this.map.addLayers(this.layers); - })); - }, - initLayer: function (layer, Layer) { - var l = new Layer(layer.url, layer.options); - this.layers.unshift(l); //unshift instead of push to keep layer ordering on map intact - //Legend LayerInfos array - var excludeLayerFromLegend = false; - if ( typeof layer.legendLayerInfos !== 'undefined' && typeof layer.legendLayerInfos.exclude !== 'undefined' ) { - excludeLayerFromLegend = layer.legendLayerInfos.exclude; - } - if ( !excludeLayerFromLegend ) { - var configuredLayerInfo = {}; - if ( typeof layer.legendLayerInfos !== 'undefined' && typeof layer.legendLayerInfos.layerInfo !== 'undefined' ) { - configuredLayerInfo = layer.legendLayerInfos.layerInfo; - } - var layerInfo = lang.mixin( { - layer: l, - title: layer.title || null - }, configuredLayerInfo ); - this.legendLayerInfos.unshift ( layerInfo ); //unshift instead of push to keep layer ordering in legend intact - } - //LayerControl LayerInfos array - this.layerControlLayerInfos.unshift({ //unshift instead of push to keep layer ordering in LayerControl intact - layer: l, - type: layer.type, - title: layer.title, - controlOptions: layer.layerControlLayerInfos - }); - if (layer.type === 'feature') { - var options = { - featureLayer: l - }; - if (layer.editorLayerInfos) { - lang.mixin(options, layer.editorLayerInfos); - } - if (options.exclude !== true) { - this.editorLayerInfos.push(options); - } - } - if (layer.type === 'dynamic' || layer.type === 'feature') { - var idOptions = { - layer: l, - title: layer.title - }; - if (layer.identifyLayerInfos) { - lang.mixin(idOptions, layer.identifyLayerInfos); - } - if (idOptions.exclude !== true) { - this.identifyLayerInfos.push(idOptions); - } - } - }, - initWidgets: function () { - var widgets = [], - paneWidgets; - - for (var key in this.config.widgets) { - if (this.config.widgets.hasOwnProperty(key)) { - var widget = lang.clone(this.config.widgets[key]); - if (widget.include) { - widget.position = ('undefined' !== typeof (widget.position)) ? widget.position : 10000; - widgets.push(widget); - } - } - } - for (var pane in this.panes) { - if (this.panes.hasOwnProperty(pane) && (pane !== 'outer' || pane !== 'center')) { - paneWidgets = array.filter(widgets, function (widget) { - return (widget.placeAt && widget.placeAt === pane); - }); - paneWidgets.sort(function (a, b) { - return a.position - b.position; - }); - array.forEach(paneWidgets, function (widget, i) { - this.widgetLoader(widget, i); - }, this); - } - } - paneWidgets = array.filter(widgets, function (widget) { - return !widget.placeAt; - }); - paneWidgets.sort(function (a, b) { - return a.position - b.position; - }); - - array.forEach(paneWidgets, function (widget, i) { - this.widgetLoader(widget, i); - }, this); - }, - togglePane: function (id, show) { - if (!this.panes[id]) { - return; - } - var domNode = this.panes[id].domNode; - if (domNode) { - var disp = (show && typeof (show) === 'string') ? show : (domStyle.get(domNode, 'display') === 'none') ? 'block' : 'none'; - domStyle.set(domNode, 'display', disp); - if (this.panes[id]._splitterWidget) { // show/hide the splitter, if found - domStyle.set(this.panes[id]._splitterWidget.domNode, 'display', disp); - } - this.positionSideBarToggle(id); - if (this.panes.outer) { - this.panes.outer.resize(); - } - } - }, - positionSideBarToggle: function (id) { - var pane = this.panes[id]; - var btn = this.collapseButtons[id]; - if (!pane || !btn) { - return; - } - var disp = domStyle.get(pane.domNode, 'display'); - var rCls = (disp === 'none') ? 'close' : 'open'; - var aCls = (disp === 'none') ? 'open' : 'close'; - domClass.remove(btn.children[0], rCls); - domClass.add(btn.children[0], aCls); - - // extra management required when the buttons - // are not in the center map pane - if (this.collapseButtonsPane === 'outer') { - var pos = (pane._splitterWidget) ? 0 : -1; - var orie = (id === 'bottom' || id === 'top') ? 'h' : 'w'; - if (disp === 'block') { // pane is open - pos += domGeom.getMarginBox(pane.domNode)[orie]; - } - if (pane._splitterWidget) { // account for a splitter - pos += domGeom.getMarginBox(pane._splitterWidget.domNode)[orie]; - } - domStyle.set(btn, id, pos.toString() + 'px'); - domStyle.set(btn, 'display', 'block'); - } - }, - - repositionSideBarButtons: function () { - var btns = ['left', 'right', 'top', 'bottom']; - array.forEach(btns, lang.hitch(this, function (id) { - this.positionSideBarToggle(id); - })); - }, - - // extra management of splitters required when the buttons - // are not in the center map pane - splitterStartDrag: function (id) { - var btn = this.collapseButtons[id]; - domStyle.set(btn, 'display', 'none'); - }, - splitterStopDrag: function (id) { - this.positionSideBarToggle(id); - }, - - _createTitlePaneWidget: function (parentId, title, position, open, canFloat, placeAt) { - var tp, options = { - title: title || 'Widget', - open: open || false, - canFloat: canFloat || false - }; - if (parentId) { - options.id = parentId; - } - if (typeof (placeAt) === 'string') { - placeAt = this.panes[placeAt]; - } - if (!placeAt) { - placeAt = this.panes.left; - } - if (placeAt) { - options.sidebar = placeAt; - tp = new FloatingTitlePane(options).placeAt(placeAt, position); - tp.startup(); - } - return tp; - }, - _createFloatingWidget: function (parentId, title) { - var options = { - title: title - }; - if (parentId) { - options.id = parentId; - } - var fw = new FloatingWidgetDialog(options); - fw.startup(); - return fw; - }, - _createContentPaneWidget: function (parentId, title, className, region, placeAt) { - var cp, options = { - title: title, - region: region || 'center' - }; - if (className) { - options.className = className; - } - if (parentId) { - options.id = parentId; - } - if (!placeAt) { - placeAt = this.panes.sidebar; - } else if (typeof (placeAt) === 'string') { - placeAt = this.panes[placeAt]; - } - if (placeAt) { - cp = new ContentPane(options).placeAt(placeAt); - cp.startup(); - } - return cp; - }, - widgetLoader: function (widgetConfig, position) { - var parentId, pnl; - - // only proceed for valid widget types - var widgetTypes = ['titlePane', 'contentPane', 'floating', 'domNode', 'invisible', 'map']; - if (array.indexOf(widgetTypes, widgetConfig.type) < 0) { - this.handleError({ - source: 'Controller', - error: 'Widget type "' + widgetConfig.type + '" (' + widgetConfig.title + ') at position ' + position + ' is not supported.' - }); - return; - } - - // build a titlePane or floating widget as the parent - if ((widgetConfig.type === 'titlePane' || widgetConfig.type === 'contentPane' || widgetConfig.type === 'floating') && (widgetConfig.id && widgetConfig.id.length > 0)) { - parentId = widgetConfig.id + '_parent'; - if (widgetConfig.type === 'titlePane') { - pnl = this._createTitlePaneWidget(parentId, widgetConfig.title, position, widgetConfig.open, widgetConfig.canFloat, widgetConfig.placeAt); - } else if (widgetConfig.type === 'contentPane') { - pnl = this._createContentPaneWidget(parentId, widgetConfig.title, widgetConfig.className, widgetConfig.region, widgetConfig.placeAt); - } else if (widgetConfig.type === 'floating') { - pnl = this._createFloatingWidget(parentId, widgetConfig.title); - } - widgetConfig.parentWidget = pnl; - } - - // 2 ways to use require to accommodate widgets that may have an optional separate configuration file - if (typeof (widgetConfig.options) === 'string') { - require([widgetConfig.options, widgetConfig.path], lang.hitch(this, 'createWidget', widgetConfig)); - } else { - require([widgetConfig.path], lang.hitch(this, 'createWidget', widgetConfig, widgetConfig.options)); - } - }, - createWidget: function (widgetConfig, options, WidgetClass) { - // set any additional options - options.id = widgetConfig.id + '_widget'; - options.parentWidget = widgetConfig.parentWidget; - - //replace config map, layerInfos arrays, etc - if (options.map) { - options.map = this.map; - } - if (options.mapRightClickMenu) { - // create right-click menu - if (!this.mapRightClickMenu) { - this.mapRightClickMenu = new Menu({ - targetNodeIds: [this.map.root], - selector: '.layersDiv' // restrict to map only - }); - this.mapRightClickMenu.startup(); - } - options.mapRightClickMenu = this.mapRightClickMenu; - } - if (options.mapClickMode) { - options.mapClickMode = this.mapClickMode.current; - } - if (options.legendLayerInfos) { - options.layerInfos = this.legendLayerInfos; - } - if (options.layerControlLayerInfos) { - options.layerInfos = this.layerControlLayerInfos; - } - if (options.editorLayerInfos) { - options.layerInfos = this.editorLayerInfos; - } - if (options.identifyLayerInfos) { - options.layerInfos = this.identifyLayerInfos; - } - - // create the widget - var pnl = options.parentWidget; - if ((widgetConfig.type === 'titlePane' || widgetConfig.type === 'contentPane' || widgetConfig.type === 'floating')) { - this[widgetConfig.id] = new WidgetClass(options, put('div')).placeAt(pnl.containerNode); - } else if (widgetConfig.type === 'domNode') { - this[widgetConfig.id] = new WidgetClass(options, widgetConfig.srcNodeRef); - } else { - this[widgetConfig.id] = new WidgetClass(options); - } - - // start up the widget - if (this[widgetConfig.id] && this[widgetConfig.id].startup && !this[widgetConfig.id]._started) { - this[widgetConfig.id].startup(); - } - }, - //centralized error handler - handleError: function (options) { - if (this.config.isDebug) { - if (typeof (console) === 'object') { - for (var option in options) { - if (options.hasOwnProperty(option)) { - console.log(option, options[option]); - } - } - } - } else { - // add growler here? - return; - } - } - }; -}); \ No newline at end of file diff --git a/viewer/js/viewer/_ConfigMixin.js b/viewer/js/viewer/_ConfigMixin.js new file mode 100644 index 000000000..999f8ab14 --- /dev/null +++ b/viewer/js/viewer/_ConfigMixin.js @@ -0,0 +1,91 @@ +define([ + 'dojo/_base/declare', + 'dojo/_base/lang', + 'dojo/Deferred' +], function ( + declare, + lang, + Deferred +) { + + return declare(null, { + + // the default name of the config file to load if ?config=configName + // is not specified + defaultConfig: 'viewer', + loadConfig: function (wait) { + + // this will be used to make any inherited methods 'wait' + var waitDeferred; + + if (wait) { + waitDeferred = new Deferred(); + + // if we need to wait for a previous deferred + // wait for it, + wait.then(lang.hitch(this, function () { + + // load the config + this.initConfigAsync().then(lang.hitch(this, function () { + + // do some stuff + this.initConfigSuccess(arguments); + + // resolve + waitDeferred.resolve(); + }), + lang.hitch(this, 'initConfigError') + ); + + })); + } else { + + waitDeferred = this.initConfigAsync(); + waitDeferred.then( + lang.hitch(this, 'initConfigSuccess'), + lang.hitch(this, 'initConfigError') + ); + } + // call any inherited methods or return a deferred + return this.inherited(arguments, [waitDeferred]) || waitDeferred; + }, + + initConfigAsync: function () { + var returnDeferred = new Deferred(); + // get the config file from the url if present + var file = 'config/' + this.defaultConfig, + s = window.location.search, + q = s.match(/config=([^&]*)/i); + if (q && q.length > 0) { + file = q[1]; + if (file.indexOf('/') < 0) { + file = 'config/' + file; + } + } + require([file], function (config) { + returnDeferred.resolve(config); + }); + return returnDeferred; + }, + + initConfigSuccess: function (config) { + this.config = config; + if (config.isDebug) { + window.app = this; //dev only + } + + // setup the map click mode + this.mapClickMode = { + current: config.defaultMapClickMode, + defaultMode: config.defaultMapClickMode + }; + }, + + initConfigError: function (err) { + this.handleError({ + source: 'Controller', + error: err + }); + } + }); +}); diff --git a/viewer/js/viewer/_ControllerBase.js b/viewer/js/viewer/_ControllerBase.js new file mode 100644 index 000000000..4ae03c5f7 --- /dev/null +++ b/viewer/js/viewer/_ControllerBase.js @@ -0,0 +1,125 @@ +/*eslint no-console: 0*/ +define([ + 'dojo/_base/declare', + 'dojo/_base/lang', + 'dojo/Deferred' +], function ( + declare, lang, Deferred +) { + return declare(null, { + + /** + * Mixes in this apps properties with the passed arguments + * @param {Object} args The properties to mixin + * @return {undefined} + */ + constructor: function (args) { + lang.mixin(this, args); + }, + + /** + * A method run before anything else, can be inherited by mixins to + * load and process the config sync or async + * @return {undefined | Deferred} If the operation is async it should return + * a deferred, otherwise it should return the value of `this.inherited(arguments)` + */ + loadConfig: function () { + return this.inherited(arguments); + }, + /** + * A method run after the config is loaded but before startup is called + * on mixins + * @return {undefined | Deferred} If the operation is async it should return + * a deferred, otherwise it should return the value of `this.inherited(arguments)` + */ + postConfig: function () { + return this.inherited(arguments); + }, + /** + * Start the application mixin chain, once the + * startupDeferred is resolved + * @return {undefined} + */ + startup: function () { + + // cache the inherited + var inherited = this.getInherited(arguments); + + // load config and process it + this.startupDeferred = this.executeSync([ + this.loadConfig, + this.postConfig + ]); + + // wait for any loading to complete + this.startupDeferred.then(lang.hitch(this, function () { + + // start up the mixin chain + inherited.apply(this); + })); + }, + /** + * executes an array of asynchronous methods synchronously + * @param {Array} methods The array of functions to execute + * @param {Deferred} deferred A deferred created inside the method and resolved once all methods are complete + * @return {Deferred} A deferred resolved once all methods are executed + */ + executeSync: function (methods, deferred) { + deferred = deferred || new Deferred(); + + // if our list is empty, resolve the deferred and quit + if (!methods || !methods.length) { + deferred.resolve(); + return deferred; + } + + // execute and remove the method from the list + var result = lang.hitch(this, methods.splice(0, 1)[0])(); + + // execute our next function once this one completes + if (result) { + result.then(lang.hitch(this, 'executeSync', methods, deferred)); + } else { + this.executeSync(methods, deferred); + } + return deferred; + + }, + + //centralized error handler + handleError: function (options) { + if (this.config.isDebug) { + if (typeof(console) === 'object') { + for (var option in options) { + if (options.hasOwnProperty(option)) { + console.log(option, options[option]); + } + } + } + } else { + // add growler here? + return; + } + }, + + mixinDeep: function (dest, source) { + //Recursively mix the properties of two objects + var empty = {}; + for (var name in source) { + if (!(name in dest) || (dest[name] !== source[name] && (!(name in empty) || empty[name] !== source[name]))) { + try { + if (source[name].constructor === Object) { + dest[name] = this.mixinDeep(dest[name], source[name]); + } else { + dest[name] = source[name]; + } + } catch (e) { + // Property in destination object not set. Create it and set its value. + dest[name] = source[name]; + } + } + } + return dest; + } + }); +}); diff --git a/viewer/js/viewer/_LayoutMixin.js b/viewer/js/viewer/_LayoutMixin.js new file mode 100644 index 000000000..4940098d1 --- /dev/null +++ b/viewer/js/viewer/_LayoutMixin.js @@ -0,0 +1,342 @@ +define([ + 'dojo/_base/declare', + 'dojo/_base/lang', + 'dojo/topic', + 'dojo/_base/array', + 'dojo/on', + 'dojo/aspect', + 'dojo/dom', + 'dojo/query', + 'dojo/dom-style', + 'dojo/dom-class', + 'dojo/dom-geometry', + 'dojo/sniff', + 'dojo/Deferred', + + 'put-selector', + + 'dijit/layout/BorderContainer', + 'dijit/layout/ContentPane', + + 'esri/dijit/PopupMobile', + + 'dojo/text!./templates/mapOverlay.html' +], function ( + declare, + lang, + topic, + array, + on, + aspect, + dom, + domQuery, + domStyle, + domClass, + domGeom, + has, + Deferred, + + put, + + BorderContainer, + ContentPane, + + PopupMobile, + + mapOverlay +) { + + return declare(null, { + + panes: { + left: { + id: 'sidebarLeft', + placeAt: 'outer', + collapsible: true, + region: 'left' + }, + center: { + id: 'mapCenter', + placeAt: 'outer', + region: 'center', + content: mapOverlay + } + }, + collapseButtons: {}, + postConfig: function () { + this.layoutDeferred = new Deferred(); + return this.inherited(arguments); + }, + + startup: function () { + this.config.layout = this.config.layout || {}; + + this.addTopics(); + this.addTitles(); + this.detectTouchDevices(); + this.initPanes(); + + this.mapDeferred.then(lang.hitch(this, 'createPanes')); + + // resolve the layout deferred + this.layoutDeferred.resolve(); + this.inherited(arguments); + }, + + // add topics for subscribing and publishing + addTopics: function () { + // toggle a sidebar pane + topic.subscribe('viewer/togglePane', lang.hitch(this, function (args) { + this.togglePane(args.pane, args.show, args.suppressEvent); + })); + + // load a widget + topic.subscribe('viewer/loadWidget', lang.hitch(this, function (args) { + this.widgetLoader(args.options, args.position); + })); + + // setup error handler. centralize the debugging + if (this.config.isDebug) { + topic.subscribe('viewer/handleError', lang.hitch(this, 'handleError')); + } + + // set the current mapClickMode + topic.subscribe('mapClickMode/setCurrent', lang.hitch(this, function (mode) { + this.mapClickMode.current = mode; + topic.publish('mapClickMode/currentSet', mode); + })); + + // set the current mapClickMode to the default mode + topic.subscribe('mapClickMode/setDefault', lang.hitch(this, function () { + topic.publish('mapClickMode/setCurrent', this.mapClickMode.defaultMode); + })); + + }, + + // set titles (if any) + addTitles: function () { + if (!this.config.titles) { + return; + } + var titles = this.config.titles; + if (titles.header) { + var headerTitleNode = dom.byId('headerTitleSpan'); + if (headerTitleNode) { + headerTitleNode.innerHTML = titles.header; + } + } + if (titles.subHeader) { + var subHeaderTitle = dom.byId('subHeaderTitleSpan'); + if (subHeaderTitle) { + subHeaderTitle.innerHTML = titles.subHeader; + } + } + if (titles.pageTitle) { + document.title = titles.pageTitle; + } + }, + // setup all the sidebar panes + initPanes: function () { + var key, + panes = this.config.panes || {}; + this.defaultPanes = lang.clone(this.panes); + for (key in this.panes) { + if (this.defaultPanes.hasOwnProperty(key)) { + panes[key] = lang.mixin(this.defaultPanes[key], panes[key]); + } + } + + var container = dom.byId(this.config.layout.container) || document.body; + this.panes.outer = new BorderContainer({ + id: 'borderContainerOuter', + design: 'sidebar', + gutters: false + }).placeAt(container); + + var options, placeAt, type; + for (key in panes) { + if (panes.hasOwnProperty(key)) { + options = lang.clone(panes[key]); + placeAt = this.panes[options.placeAt] || this.panes.outer; + options.id = options.id || key; + type = options.type; + delete options.placeAt; + delete options.type; + delete options.collapsible; + if (placeAt) { + if (type === 'border') { + this.panes[key] = new BorderContainer(options).placeAt(placeAt); + } else if (options.region) { + this.panes[key] = new ContentPane(options).placeAt(placeAt); + } + } + } + } + this.panes.outer.startup(); + }, + + createPanes: function () { + var key, + panes = this.config.panes || {}; + for (key in this.panes) { + if (this.defaultPanes.hasOwnProperty(key)) { + panes[key] = lang.mixin(this.defaultPanes[key], panes[key]); + } + } + // where to place the buttons + // either the center map pane or the outer pane? + this.collapseButtonsPane = this.config.collapseButtonsPane || 'outer'; + + for (key in panes) { + if (panes.hasOwnProperty(key)) { + if (panes[key].collapsible) { + this.collapseButtons[key] = put(this.panes[this.collapseButtonsPane].domNode, 'div.sidebarCollapseButton.sidebar' + key + 'CollapseButton.sidebarCollapseButton' + ((key === 'bottom' || key === 'top') ? 'Vert' : 'Horz') + ' div.dijitIcon.button.close').parentNode; + on(this.collapseButtons[key], 'click', lang.hitch(this, 'togglePane', key, null, false)); + this.positionSideBarToggle(key); + if (this.collapseButtonsPane === 'outer') { + var splitter = this.panes[key]._splitterWidget; + if (splitter) { + aspect.after(splitter, '_startDrag', lang.hitch(this, '_splitterStartDrag', key)); + aspect.after(splitter, '_stopDrag', lang.hitch(this, '_splitterStopDrag', key)); + } + } + } + if (panes[key].open !== undefined) { + this.togglePane(key, panes[key].open, true); + } + if (key !== 'center' && this.panes[key]._splitterWidget) { + domClass.add(this.map.root.parentNode, 'pane' + key); + if (key === 'right' && this.panes.top) { + domClass.add(this.panes.top.domNode, 'pane' + key); + } + if (key === 'right' && this.panes.bottom) { + domClass.add(this.panes.bottom.domNode, 'pane' + key); + } + if (key === 'left' && this.panes.top) { + domClass.add(this.panes.top.domNode, 'pane' + key); + } + if (key === 'left' && this.panes.bottom) { + domClass.add(this.panes.bottom.domNode, 'pane' + key); + } + } + } + } + + this.resizeLayout(); + }, + + togglePane: function (id, show, suppressEvent) { + if (!this.panes[id]) { + return; + } + var domNode = this.panes[id].domNode; + if (domNode) { + var oldDisp = domStyle.get(domNode, 'display'); + var newDisp; + + if (typeof(show) === 'string' && (show === 'none' || show === 'block')) { + // Set (CSS Display Property) + newDisp = show; + } else if (typeof(show) === 'boolean') { + // Set (boolean) + newDisp = (show) ? 'block' : 'none'; + } else if (show === undefined || show === null) { + // Toggle + newDisp = (oldDisp === 'none') ? 'block' : 'none'; + } else { + this.handleError({ + source: '_LayoutMixin', + error: 'Invalid type passed as "show" property of "togglePane" function : ' + typeof(show) + }); + return; + } + show = (newDisp === 'block'); + + if (newDisp !== oldDisp) { + domStyle.set(domNode, 'display', newDisp); + if (this.panes[id]._splitterWidget) { // show/hide the splitter, if found + domStyle.set(this.panes[id]._splitterWidget.domNode, 'display', newDisp); + } + this.positionSideBarToggle(id); + if (this.panes.outer) { + this.panes.outer.resize(); + } + + if (!suppressEvent) { + topic.publish('viewer/onTogglePane', { + pane: id, + show: show + }); + } + } + } + }, + + positionSideBarToggle: function (id) { + var pane = this.panes[id]; + var btn = this.collapseButtons[id]; + if (!pane || !btn) { + return; + } + var disp = domStyle.get(pane.domNode, 'display'); + var rCls = (disp === 'none') ? 'close' : 'open'; + var aCls = (disp === 'none') ? 'open' : 'close'; + domClass.remove(btn.children[0], rCls); + domClass.add(btn.children[0], aCls); + + // extra management required when the buttons + // are not in the center map pane + if (this.collapseButtonsPane === 'outer') { + var pos = (pane._splitterWidget) ? 0 : -1; + var orie = (id === 'bottom' || id === 'top') ? 'h' : 'w'; + if (disp === 'block') { // pane is open + pos += domGeom.getMarginBox(pane.domNode)[orie]; + } + if (pane._splitterWidget) { // account for a splitter + pos += domGeom.getMarginBox(pane._splitterWidget.domNode)[orie]; + } + domStyle.set(btn, id, pos.toString() + 'px'); + domStyle.set(btn, 'display', 'block'); + } + }, + + repositionSideBarButtons: function () { + var btns = ['left', 'right', 'top', 'bottom']; + array.forEach(btns, lang.hitch(this, function (id) { + this.positionSideBarToggle(id); + })); + }, + + resizeLayout: function () { + this.panes.outer.resize(); + }, + + // extra management of splitters required when the buttons + // are not in the center map pane + _splitterStartDrag: function (id) { + var btn = this.collapseButtons[id]; + domStyle.set(btn, 'display', 'none'); + }, + _splitterStopDrag: function (id) { + this.positionSideBarToggle(id); + }, + + // simple feature detection. kinda like dojox/mobile without the overhead + detectTouchDevices: function () { + if (has('touch') && (has('ios') || has('android') || has('bb'))) { + has.add('mobile', true); + if (screen.availWidth < 500 || screen.availHeight < 500) { + has.add('phone', true); + } else { + has.add('tablet', true); + } + + // use the mobile popup for phones + if (has('phone') && !this.config.mapOptions.infoWindow) { + this.config.mapOptions.infoWindow = new PopupMobile(null, put('div')); + } + } + + } + }); +}); diff --git a/viewer/js/viewer/_MapMixin.js b/viewer/js/viewer/_MapMixin.js new file mode 100644 index 000000000..71e658d0a --- /dev/null +++ b/viewer/js/viewer/_MapMixin.js @@ -0,0 +1,254 @@ +define([ + 'dojo/_base/declare', + 'dojo/_base/lang', + 'dojo/on', + 'dojo/dom', + 'dojo/_base/array', + 'dojo/Deferred', + + 'esri/map', + + 'esri/IdentityManager' + +], function ( + declare, + lang, + on, + dom, + array, + Deferred, + + Map +) { + + return declare(null, { + + postConfig: function () { + this.mapDeferred = new Deferred(); + return this.inherited(arguments); + }, + + startup: function () { + this.inherited(arguments); + this.layoutDeferred.then(lang.hitch(this, 'initMapAsync')); + }, + + initMapAsync: function () { + var returnDeferred = new Deferred(); + var returnWarnings = []; + + this.createMap(returnWarnings).then( + lang.hitch(this, '_createMapResult', returnDeferred, returnWarnings) + ); + returnDeferred.then(lang.hitch(this, 'initMapComplete')); + return returnDeferred; + }, + + createMap: function (returnWarnings) { + + // mixins override the default createMap method and return a deferred + var result = this.inherited(arguments); + if (result) { + return result; + } + + // otherwise we can create the map + var mapDeferred = new Deferred(), + container = dom.byId(this.config.layout.map) || 'mapCenter'; + + this.map = new Map(container, this.config.mapOptions); + + // let some other mixins modify or add map items async + var wait = this.inherited(arguments); + if (wait) { + wait.then(function (warnings) { + if (warnings) { + returnWarnings = returnWarnings.concat(warnings); + } + mapDeferred.resolve(returnWarnings); + }); + } else { + mapDeferred.resolve(returnWarnings); + } + return mapDeferred; + }, + + _createMapResult: function (returnDeferred, returnWarnings) { + if (this.map) { + if (!this.config.webMapId && this.config.mapOptions && this.config.mapOptions.basemap) { + this.map.on('load', lang.hitch(this, '_initLayers', returnWarnings)); + } else { + this._initLayers(returnWarnings); + } + + if (this.config.operationalLayers && this.config.operationalLayers.length > 0) { + on.once(this.map, 'layers-add-result', lang.hitch(this, '_onLayersAddResult', returnDeferred, returnWarnings)); + } else { + returnDeferred.resolve(returnWarnings); + } + } else { + returnDeferred.resolve(returnWarnings); + } + return returnDeferred; + }, + + _onLayersAddResult: function (returnDeferred, returnWarnings, lyrsResult) { + array.forEach(lyrsResult.layers, function (addedLayer) { + if (addedLayer.success !== true) { + returnWarnings.push(addedLayer.error); + } + }, this); + returnDeferred.resolve(returnWarnings); + }, + + _initLayers: function (returnWarnings) { + this.layers = []; + var layerTypes = { + csv: 'esri/layers/CSVLayer', + dataadapter: 'esri/layers/DataAdapterFeatureLayer', //untested + dynamic: 'esri/layers/ArcGISDynamicMapServiceLayer', + feature: 'esri/layers/FeatureLayer', + georss: 'esri/layers/GeoRSSLayer', + image: 'esri/layers/ArcGISImageServiceLayer', + imagevector: 'esri/layers/ArcGISImageServiceVectorLayer', + kml: 'esri/layers/KMLLayer', + label: 'esri/layers/LabelLayer', //untested + mapimage: 'esri/layers/MapImageLayer', //untested + osm: 'esri/layers/OpenStreetMapLayer', + raster: 'esri/layers/RasterLayer', + stream: 'esri/layers/StreamLayer', + tiled: 'esri/layers/ArcGISTiledMapServiceLayer', + vectortile: 'esri/layers/VectorTileLayer', + webtiled: 'esri/layers/WebTiledLayer', + wfs: 'esri/layers/WFSLayer', + wms: 'esri/layers/WMSLayer', + wmts: 'esri/layers/WMTSLayer' //untested + }; + // add any user-defined layer types such as https://github.com/Esri/geojson-layer-js + layerTypes = lang.mixin(layerTypes, this.config.layerTypes || {}); + // loading all the required modules first ensures the layer order is maintained + var modules = []; + array.forEach(this.config.operationalLayers, function (layer) { + var type = layerTypes[layer.type]; + if (type) { + modules.push(type); + } else { + returnWarnings.push('Layer type "' + layer.type + '" is not supported: '); + } + }, this); + + require(modules, lang.hitch(this, function () { + array.forEach(this.config.operationalLayers, function (layer) { + var type = layerTypes[layer.type]; + if (type) { + require([type], lang.hitch(this, '_initLayer', layer)); + } + }, this); + this.map.addLayers(this.layers); + })); + }, + + _initLayer: function (layer, Layer) { + var l; + if (layer.url) { + l = new Layer(layer.url, layer.options); + } else { + l = new Layer(layer.options); + } + this.layers.unshift(l); //unshift instead of push to keep layer ordering on map intact + + //Legend LayerInfos array + var excludeLayerFromLegend = false; + if (typeof layer.legendLayerInfos !== 'undefined' && typeof layer.legendLayerInfos.exclude !== 'undefined') { + excludeLayerFromLegend = layer.legendLayerInfos.exclude; + } + if (!excludeLayerFromLegend) { + var configuredLayerInfo = {}; + if (typeof layer.legendLayerInfos !== 'undefined' && typeof layer.legendLayerInfos.layerInfo !== 'undefined') { + configuredLayerInfo = layer.legendLayerInfos.layerInfo; + } + var layerInfo = lang.mixin({ + layer: l, + title: layer.title || null + }, configuredLayerInfo); + this.legendLayerInfos.unshift(layerInfo); //unshift instead of push to keep layer ordering in legend intact + } + + //LayerControl LayerInfos array + this.layerControlLayerInfos.unshift({ //unshift instead of push to keep layer ordering in LayerControl intact + layer: l, + type: layer.type, + title: layer.title, + controlOptions: layer.layerControlLayerInfos + }); + + if (layer.type === 'feature') { + var options = { + featureLayer: l + }; + if (layer.editorLayerInfos) { + lang.mixin(options, layer.editorLayerInfos); + } + if (options.exclude !== true) { + this.editorLayerInfos.push(options); + } + } + + if (layer.type === 'dynamic' || layer.type === 'feature') { + var idOptions = { + layer: l, + title: layer.title + }; + if (layer.identifyLayerInfos) { + lang.mixin(idOptions, layer.identifyLayerInfos); + } + if (idOptions.exclude !== true) { + this.identifyLayerInfos.push(idOptions); + } + } + }, + initMapComplete: function (warnings) { + if (warnings && warnings.length > 0) { + this.handleError({ + source: 'Controller', + error: warnings.join(', ') + }); + } + + if (this.map) { + + this.map.on('resize', function (evt) { + var pnt = evt.target.extent.getCenter(); + setTimeout(function () { + evt.target.centerAt(pnt); + }, 100); + }); + + // resolve the map deferred + this.mapDeferred.resolve(this.map); + } + + }, + + initMapError: function (err) { + this.handleError({ + source: 'Controller', + error: err + }); + }, + + resizeMap: function () { + if (this.map) { + this.map.resize(); + } + }, + + getMapHeight: function () { + if (this.map) { + return this.map.height; + } else { + return 0; + } + } + }); +}); diff --git a/viewer/js/viewer/_WebMapMixin.js b/viewer/js/viewer/_WebMapMixin.js new file mode 100644 index 000000000..106a302b2 --- /dev/null +++ b/viewer/js/viewer/_WebMapMixin.js @@ -0,0 +1,233 @@ +define([ + 'dojo/_base/declare', + 'dojo/_base/lang', + 'dojo/_base/array', + 'dojo/dom', + + 'esri/arcgis/utils', + 'esri/units' + +], function ( + declare, + lang, + array, + dom, + + arcgisUtils, + units +) { + return declare(null, { + startup: function () { + this.inherited(arguments); + // this.mapDeferred.then(lang.hitch(this, '_initWebMap')); + }, + + createMap: function () { + var webMapOptions = this.config.webMapOptions || {}; + if (!webMapOptions.mapOptions && this.config.mapOptions) { + webMapOptions.mapOptions = this.config.mapOptions; + } + var container = dom.byId(this.config.layout.map) || 'mapCenter'; + + var mapDeferred = arcgisUtils.createMap(this.config.webMapId, container, webMapOptions); + mapDeferred.then(lang.hitch(this, function (response) { + this.webMap = { + clickEventHandle: response.clickEventHandle, + clickEventListener: response.clickEventListener, + itemInfo: response.itemInfo + }; + this.map = response.map; + + // get the layerInfos from the webmap + this._initWebMapLayerInfos(response); + + // add any widgets included in the webmap + this._initWebMapWidgets(response); + })); + return mapDeferred; + + }, + + _initWebMapLayerInfos: function (response) { + if (this.config.layerControlLayerInfos) { + // get the layerInfos for the layerControl widget from the config + this.layerControlLayerInfos = this.config.layerControlLayerInfos; + + } else if (response.itemInfo && response.itemInfo.itemData) { + // get the layerInfos for the layerControl widget from the webmap + + // https://developers.arcgis.com/web-map-specification/objects/operationalLayers/ + var layerTypes = { + 'CSV': 'csv', + 'ArcGISMapServiceLayer': 'dynamic', + 'ArcGISFeatureLayer': 'feature', + 'GeoRSSLayer': 'georss', + 'ArcGISImageServiceLayer': 'image', + 'esri/layers/ArcGISImageServiceVectorLayer': 'imagevector', + 'KML': 'kml', + 'ArcGISStreamLayer': 'stream', + 'ArcGISTiledMapServiceLayer': 'tiled', + 'VectorTileLayer': 'vectortile', + 'WebTiledLayer': 'webtiled', + 'WMS': 'wms' + + /* + Are these supported in Webmaps? + + 'dataadapter': 'esri/layer/DataAdapterFeatureLayer', //untested + label: 'esri/layers/LabelLayer', //untested + mapimage: 'esri/layers/MapImageLayer', //untested + osm: 'esri/layers/OpenStreetMapLayer', + raster: 'esri/layers/RasterLayer', + 'wfs': 'esri/layers/WFSLayer', + 'esri/layers/WMTS': 'wmts' + */ + }; + + var operationalLayers = response.itemInfo.itemData.operationalLayers; + array.forEach(operationalLayers, lang.hitch(this, function (layer) { + var layerType = layerTypes[layer.layerType]; + if (layerType) { + this.layerControlLayerInfos.push({ + layer: layer.layerObject, + type: layerType, + title: layer.title + }); + } + })); + } + + if (this.config.legendLayerInfos) { + // get the layerInfos for the legend widget from the config + this.legendLayerInfos = this.config.legendLayerInfos; + } else { + // get the layerInfos for the legend widget from the webmap + this.legendLayerInfos = arcgisUtils.getLegendLayers(response); + } + }, + + _initWebMapWidgets: function (response) { + if (!response.itemInfo || !response.itemInfo.itemData) { + return; + } + + // existing widgets if any + var widgets = this.config.widgets; + + var bookmarks = response.itemInfo.itemData.bookmarks; + if (bookmarks && bookmarks.length > 0) { + widgets.bookmarks = this.mixinDeep({ + include: true, + id: 'bookmarks', + type: 'titlePane', + path: 'gis/dijit/Bookmarks', + title: 'Bookmarks', + open: false, + position: 999, + options: { + map: true, + editable: false, + bookmarks: bookmarks + } + }, widgets.bookmarks || {}); + } + + if (response.itemInfo.itemData.applicationProperties) { + // https://developers.arcgis.com/web-map-specification/objects/viewing/ + var viewing = response.itemInfo.itemData.applicationProperties.viewing; + // possible widgets: basemapGallery, measure, routing, search + + if (viewing.basemapGallery && viewing.basemapGallery.enabled) { + if (!widgets.basemaps || !widgets.basemaps.include) { // basemap gallery widget and basemaps widget cannot co-exist + widgets.basemapGallery = this.mixinDeep({ + include: true, + id: 'basemapGallery', + type: 'domNode', + path: 'gis/dijit/BasemapGallery', + srcNodeRef: 'basemapsDijit', + options: { + map: true + } + }, widgets.basemapGallery || {}); + } + } + + if (viewing.routing && viewing.routing.enabled) { + widgets.directions = this.mixinDeep({ + include: true, + id: 'directions', + type: 'titlePane', + path: 'gis/dijit/Directions', + title: 'Directions', + open: false, + position: 999, + options: { + map: true, + mapRightClickMenu: true, + options: { + routeTaskUrl: 'https://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Network/USA/NAServer/Route', + routeParams: { + directionsLanguage: 'en-US', + directionsLengthUnits: units.MILES + }, + active: false //for 3.12, starts active by default, which we dont want as it interfears with mapClickMode + } + } + }, widgets.directions || {}); + } + + if (viewing.measure && viewing.measure.enabled) { + widgets.measure = this.mixinDeep({ + include: true, + id: 'measurement', + type: 'titlePane', + path: 'gis/dijit/Measurement', + title: 'Measurement', + open: false, + position: 999, + options: { + map: true, + mapClickMode: true, + defaultAreaUnit: units.SQUARE_MILES, + defaultLengthUnit: units.MILES + } + }, widgets.measure || {}); + } + + if (viewing.search && viewing.search.enabled) { + widgets.search = this.mixinDeep({ + include: true, + type: 'domNode', + path: 'esri/dijit/Search', + srcNodeRef: 'geocoderButton', + options: { + map: true, + visible: true, + enableButtonMode: true, + expanded: true, + disablePlaceFinder: viewing.search.disablePlaceFinder, + hintText: viewing.search.hintText, + layers: viewing.search.layers + } + }, widgets.search || {}); + } + } + + // https://developers.arcgis.com/web-map-specification/objects/widgets/ + if (response.itemInfo.itemData.widgets) { + var timeSlider = response.itemInfo.itemData.widgets.timeSlider; + if (timeSlider) { + widgets.timeSlider = this.mixinDeep({ + include: true, + type: 'domNode', + path: 'esri/dijit/TimeSlider', + srcNodeRef: 'geocoderButton', + options: lang.mixin({ + map: true + }, timeSlider) + }, widgets.slider || {}); + } + } + } + }); +}); diff --git a/viewer/js/viewer/_WidgetsMixin.js b/viewer/js/viewer/_WidgetsMixin.js new file mode 100644 index 000000000..8ab99d897 --- /dev/null +++ b/viewer/js/viewer/_WidgetsMixin.js @@ -0,0 +1,321 @@ +define([ + 'dojo/_base/declare', + 'dojo/_base/array', + 'dojo/_base/lang', + 'dojo/promise/all', + 'dojo/Deferred', + + 'put-selector', + + 'dijit/Menu', + 'dijit/layout/ContentPane', + + 'gis/dijit/FloatingTitlePane', + 'gis/dijit/FloatingWidgetDialog' + +], function ( + declare, + array, + lang, + promiseAll, + Deferred, + + put, + + Menu, + ContentPane, + + FloatingTitlePane, + FloatingWidgetDialog +) { + + return declare(null, { + + legendLayerInfos: [], + editorLayerInfos: [], + identifyLayerInfos: [], + layerControlLayerInfos: [], + + widgets: {}, + widgetTypes: ['titlePane', 'contentPane', 'floating', 'domNode', 'invisible', 'map', 'layer', 'layout', 'loading'], + postConfig: function (wait) { + + var waitDeferred; + if (wait) { + waitDeferred = new Deferred(); + + wait.then(lang.hitch(this, function () { + // load loading widgets + promiseAll(this.createWidgets(['loading'])).then(waitDeferred.resolve); + })); + } else { + var deferreds = this.createWidgets(['loading']); + if (deferreds && deferreds.length) { + waitDeferred = promiseAll(deferreds); + } + } + + return this.inherited(arguments) || waitDeferred; + }, + startup: function () { + this.inherited(arguments); + if (this.mapDeferred) { + this.mapDeferred.then(lang.hitch(this, 'createWidgets', ['map', 'layer'])); + } + if (this.layoutDeferred) { + promiseAll([this.mapDeferred, this.layoutDeferred]) + .then(lang.hitch(this, 'createWidgets', null)); + } + }, + + createWidgets: function (widgetTypes) { + var widgets = [], + paneWidgets; + + widgetTypes = widgetTypes || this.widgetTypes; + for (var key in this.config.widgets) { + if (this.config.widgets.hasOwnProperty(key)) { + var widget = lang.clone(this.config.widgets[key]); + widget.widgetKey = widget.widgetKey || widget.id || key; + if (widget.include && (!this.widgets[widget.widgetKey]) && (array.indexOf(widgetTypes, widget.type) >= 0)) { + widget.position = (typeof(widget.position) !== 'undefined') ? widget.position : 10000; + if ((widget.type === 'titlePane' || widget.type === 'contentPane') && !widget.placeAt) { + widget.placeAt = 'left'; + } + widgets.push(widget); + this.widgets[key] = true; // will be replaced by actual widget once created + } + } + } + + function getPaneWidgets (pane) { + paneWidgets = array.filter(widgets, function (paneWidget) { + return (paneWidget.placeAt && paneWidget.placeAt === pane); + }); + return paneWidgets; + } + + for (var pane in this.panes) { + if (this.panes.hasOwnProperty(pane) && pane !== 'outer' && pane !== 'center') { + paneWidgets = getPaneWidgets(pane); + paneWidgets.sort(function (a, b) { + return a.position - b.position; + }); + if (paneWidgets.length > 0 && paneWidgets[0].position !== 0) { + paneWidgets[0].position = 0; + } + array.forEach(paneWidgets, function (paneWidget, i) { + this.widgetLoader(paneWidget, i); + }, this); + } + } + paneWidgets = array.filter(widgets, function (paneWidget) { + return !paneWidget.placeAt; + }); + paneWidgets.sort(function (a, b) { + return a.position - b.position; + }); + var deferreds = []; + array.forEach(paneWidgets, function (paneWidget, i) { + var def = this.widgetLoader(paneWidget, i); + if (def) { + deferreds.push(def); + } + }, this); + return deferreds; + }, + + widgetLoader: function (widgetConfig, position) { + var parentId, pnl; + + var widgetTypes = this.widgetTypes; + // add any user-defined widget types + widgetTypes = widgetTypes.concat(this.config.widgetTypes || []); + // only proceed for valid widget types + if (array.indexOf(widgetTypes, widgetConfig.type) < 0) { + this.handleError({ + source: 'Controller', + error: 'Widget type "' + widgetConfig.type + '" (' + widgetConfig.title + ') at position ' + position + ' is not supported.' + }); + return null; + } + + if (position) { + widgetConfig.position = position; + } + + // build a titlePane or floating widget as the parent + if ((widgetConfig.type === 'titlePane' || widgetConfig.type === 'contentPane' || widgetConfig.type === 'floating')) { + parentId = widgetConfig.widgetKey + '_parent'; + if (widgetConfig.type === 'titlePane') { + pnl = this._createTitlePaneWidget(parentId, widgetConfig); + } else if (widgetConfig.type === 'contentPane') { + pnl = this._createContentPaneWidget(parentId, widgetConfig); + } else if (widgetConfig.type === 'floating') { + pnl = this._createFloatingWidget(parentId, widgetConfig); + } + widgetConfig.parentWidget = pnl; + this._showWidgetLoader(pnl); + } + + // 2 ways to use require to accommodate widgets that may have an optional separate configuration file + var deferred = new Deferred(); + if (typeof(widgetConfig.options) === 'string') { + require([widgetConfig.options, widgetConfig.path], lang.hitch(this, function (options, WidgetClass) { + deferred.resolve(); + this.createWidget(widgetConfig, options, WidgetClass); + })); + } else { + require([widgetConfig.path], lang.hitch(this, function (WidgetClass) { + deferred.resolve(); + this.createWidget(widgetConfig, widgetConfig.options, WidgetClass); + })); + } + return deferred; + }, + + createWidget: function (widgetConfig, options, WidgetClass) { + var key = widgetConfig.widgetKey; + if (!key) { + return; + } + + // set any additional options + options = this._setWidgetOptions(widgetConfig, options); + + // create the widget + var pnl = options.parentWidget; + var widgets = this.widgets; + if ((widgetConfig.type === 'titlePane' || widgetConfig.type === 'contentPane' || widgetConfig.type === 'floating')) { + widgets[key] = new WidgetClass(options, put('div')).placeAt(pnl.containerNode); + } else if (widgetConfig.type === 'domNode') { + widgets[key] = new WidgetClass(options, widgetConfig.srcNodeRef); + } else { + widgets[key] = new WidgetClass(options); + } + // start up the widget + if (widgets[key] && widgets[key].startup && !widgets[key]._started) { + widgets[key].startup(); + } + this._hideWidgetLoader(pnl); + }, + + _setWidgetOptions: function (widgetConfig, options) { + if (widgetConfig.id) { + options.id = widgetConfig.id + '_widget'; + } + options.parentWidget = widgetConfig.parentWidget; + + //replace config map, layerInfos arrays, etc + if (options.map) { + options.map = this.map; + } + if (options.mapRightClickMenu) { + // create right-click menu + if (!this.mapRightClickMenu) { + this.mapRightClickMenu = new Menu({ + targetNodeIds: [this.map.root], + selector: '.esriMapLayers' // restrict to map only + }); + this.mapRightClickMenu.startup(); + } + options.mapRightClickMenu = this.mapRightClickMenu; + } + if (options.mapClickMode) { + options.mapClickMode = this.mapClickMode.current; + } + if (options.legendLayerInfos) { + options.layerInfos = this.legendLayerInfos; + } + if (options.layerControlLayerInfos) { + options.layerInfos = this.layerControlLayerInfos; + } + if (options.editorLayerInfos) { + options.layerInfos = this.editorLayerInfos; + } + if (options.identifyLayerInfos) { + options.layerInfos = this.identifyLayerInfos; + } + return options; + }, + + _showWidgetLoader: function (pnl) { + if (pnl && pnl.containerNode) { + pnl.loadingNode = put(pnl.containerNode, 'div.widgetLoader i.fa.fa-spinner.fa-pulse.fa-fw').parentNode; + } + }, + + _hideWidgetLoader: function (pnl) { + if (pnl && pnl.loadingNode) { + require(['dojo/domReady!'], function () { + put(pnl.loadingNode, '!'); + }); + } + }, + + _createTitlePaneWidget: function (parentId, widgetConfig) { + var tp, + options = lang.mixin({ + title: widgetConfig.title || 'Widget', + iconClass: widgetConfig.iconClass, + open: widgetConfig.open || false, + canFloat: widgetConfig.canFloat || false, + resizable: widgetConfig.resizable || false + }, widgetConfig.paneOptions || {}); + if (parentId) { + options.id = parentId; + } + var placeAt = widgetConfig.placeAt; + if (typeof(placeAt) === 'string') { + placeAt = this.panes[placeAt]; + } + if (!placeAt) { + placeAt = this.panes.left; + } + if (placeAt) { + options.sidebar = placeAt; + tp = new FloatingTitlePane(options).placeAt(placeAt, widgetConfig.position); + tp.startup(); + } + return tp; + }, + + _createFloatingWidget: function (parentId, widgetConfig) { + var options = lang.mixin({ + title: widgetConfig.title + }, widgetConfig.paneOptions || {}); + if (parentId) { + options.id = parentId; + } + var fw = new FloatingWidgetDialog(options); + fw.startup(); + return fw; + }, + + _createContentPaneWidget: function (parentId, widgetConfig) { + var cp, + options = lang.mixin({ + title: widgetConfig.title, + region: widgetConfig.region || 'center' + }, widgetConfig.paneOptions || {}); + if (widgetConfig.className) { + options.className = widgetConfig.className; + } + if (parentId) { + options.id = parentId; + } + var placeAt = widgetConfig.placeAt; + if (!placeAt) { + placeAt = this.panes.left; + } else if (typeof(placeAt) === 'string') { + placeAt = this.panes[placeAt]; + } + if (placeAt) { + cp = new ContentPane(options).placeAt(placeAt); + cp.startup(); + } + return cp; + } + + }); +}); diff --git a/viewer/js/viewer/templates/leftContent.html b/viewer/js/viewer/templates/leftContent.html deleted file mode 100644 index e69de29bb..000000000 diff --git a/viewer/proxy/PROXY_README.md b/viewer/proxy/PROXY_README.md deleted file mode 100755 index 371a189b3..000000000 --- a/viewer/proxy/PROXY_README.md +++ /dev/null @@ -1,96 +0,0 @@ -DotNet Proxy File -================= - -A .NET proxy that handles support for -* Accessing cross domain resources -* Requests that exceed 2048 characters -* Accessing resources secured with token based authentication. -* [OAuth 2.0 app logins](https://developers.arcgis.com/en/authentication). -* Enabling logging -* Both resource and referer based rate limiting - -##Instructions - -* Download and unzip the .zip file or clone the repository. You can download [a released version](https://github.com/Esri/resource-proxy/releases) (recommended) or the [most recent daily build](https://github.com/Esri/resource-proxy/archive/master.zip). -* Install the contents of the DotNet folder as a .NET Web Application, specifying a .NET 4.0 application pool or later -* Test that the proxy is able to forward requests directly in the browser using: -``` -http://[yourmachine]/DotNet/proxy.ashx?http://services.arcgisonline.com/ArcGIS/rest/services/?f=pjson -``` -* Edit the proxy.config file in a text editor to set up your proxy configuration settings. -* Update your application to use the proxy for the specified services. In this JavaScript example requests to route.arcgis.com will utilize the proxy. - -``` - urlUtils.addProxyRule({ - urlPrefix: "route.arcgis.com", - proxyUrl: "http://[yourmachine]/proxy/proxy.ashx" - }); -``` -* Security tip: By default, the proxy.config allows any referrer. To lock this down, replace the ```*``` in the ```allowedReferers``` property with your own application URLs. - -##Proxy Configuration Settings - -* Use the ProxyConfig tag to specify the following proxy level settings. - * **mustMatch="true"** : When true only the sites listed using serverUrl will be proxied. Set to false to proxy any site, which can be useful in testing. However, we recommend setting it to "true" for production sites. - * **allowedReferers="http://server.com/app1,http://server.com/app2"** : A comma-separated list of referer URLs. Only requests coming from referers in the list will be proxied. -* Add a new \ entry for each service that will use the proxy. The proxy.config allows you to use the serverUrl tag to specify one or more ArcGIS Server services that the proxy will forward requests to. The serverUrl tag has the following attributes: - * **url**: Location of the ArcGIS Server service (or other URL) to proxy. Specify either the specific URL or the root (in which case you should set matchAll="false"). - * **matchAll="true"**: When true all requests that begin with the specified URL are forwarded. Otherwise, the URL requested must match exactly. - * **username**: Username to use when requesting a token - if needed for ArcGIS Server token based authentication. - * **password**: Password to use when requesting a token - if needed for ArcGIS Server token based authentication. - * **clientId**. Used with clientSecret for OAuth authentication to obtain a token - if needed for OAuth 2.0 authentication. **NOTE**: If used to access hosted services, the service(s) must be owned by the user accessing it, (with the exception of credit-based esri services, e.g. routing, geoenrichment, etc.) - * **clientSecret**: Used with clientId for OAuth authentication to obtain a token - if needed for OAuth 2.0 authentication. - * **oauth2Endpoint**: When using OAuth 2.0 authentication specify the portal specific OAuth 2.0 authentication endpoint. The default value is https://www.arcgis.com/sharing/oauth2/. - * **accessToken**: OAuth2 access token to use instead of on-demand access-token generation using clientId & clientSecret. - * **rateLimit**: The maximum number of requests with a particular referer over the specified **rateLimitPeriod**. - * **rateLimitPeriod**: The time period (in minutes) within which the specified number of requests (rate_limit) sent with a particular referer will be tracked. The default value is 60 (one hour). - -Note: Refresh the proxy application after updates to the proxy.config have been made. - -Example of proxy using application credentials and limiting requests to 10/minute -``` - - -``` -Example of a tag for a resource which does not require authentication -``` - - -``` -Note: You may have to refresh the proxy application after updates to the proxy.config have been made. - -##Folders and Files - -The proxy consists of the following files: -* proxy.config: This file contains the configuration settings for the proxy. This is where you will define all the resources that will use the proxy. After updating this file you might need to refresh the proxy application using IIS tools in order for the changes to take effect. -* **Important note:** In order to keep your credentials safe, ensure that your web server will not display the text inside your proxy.config in the browser (ie: http://[yourmachine]/proxy/proxy.config). -* proxy.ashx: The actual proxy application. In most cases you will not need to modify this file. -* web.config: An XML file that stores ASP.NET configuration data. Use this file to configure logging for the proxy. By default the proxy will write log messages to a file named auth_proxy.log located in 'C:\Temp\Shared\proxy_logs'. Note that the folder location needs to exist in order for the log file to be successfully created. -##Requirements - -* ASP.NET 4.0 or greater (4.5 is required on Windows 8/Server 2012, see [this article] (http://www.iis.net/learn/get-started/whats-new-in-iis-8/iis-80-using-aspnet-35-and-aspnet-45) for more information) - -##Issues - -Found a bug or want to request a new feature? Let us know by submitting an issue. - -##Contributing - -All contributions are welcome. - -##Licensing - -Copyright 2014 Esri - -Licensed under the Apache License, Version 2.0 (the "License"); -You may not use this file except in compliance with the License. -You may obtain a copy of the License at -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for specific language governing permissions and limitations under the license. diff --git a/viewer/proxy/Web.config b/viewer/proxy/Web.config deleted file mode 100755 index 8d1a40128..000000000 --- a/viewer/proxy/Web.config +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/viewer/proxy/proxy.ashx b/viewer/proxy/proxy.ashx deleted file mode 100755 index 6446e630d..000000000 --- a/viewer/proxy/proxy.ashx +++ /dev/null @@ -1,834 +0,0 @@ -<%@ WebHandler Language="C#" Class="proxy" %> - -/* - * DotNet proxy client. - * - * Version 1.1 beta - * See https://github.com/Esri/resource-proxy for more information. - * - */ - -#define TRACE -using System; -using System.IO; -using System.Web; -using System.Xml.Serialization; -using System.Web.Caching; -using System.Collections.Concurrent; -using System.Diagnostics; - -public class proxy : IHttpHandler { - - class RateMeter { - double _rate; //internal rate is stored in requests per second - int _countCap; - double _count = 0; - DateTime _lastUpdate = DateTime.Now; - - public RateMeter(int rate_limit, int rate_limit_period) { - _rate = (double) rate_limit / rate_limit_period / 60; - _countCap = rate_limit; - } - - //called when rate-limited endpoint is invoked - public bool click() { - TimeSpan ts = DateTime.Now - _lastUpdate; - _lastUpdate = DateTime.Now; - //assuming uniform distribution of requests over time, - //reducing the counter according to # of seconds passed - //since last invocation - _count = Math.Max(0, _count - ts.TotalSeconds * _rate); - if (_count <= _countCap) { - //good to proceed - _count++; - return true; - } - return false; - } - - public bool canBeCleaned() { - TimeSpan ts = DateTime.Now - _lastUpdate; - return _count - ts.TotalSeconds * _rate <= 0; - } - } - - private static string PROXY_REFERER = "http://localhost/proxy/proxy.ashx"; - private static string DEFAULT_OAUTH = "https://www.arcgis.com/sharing/oauth2/"; - private static int CLEAN_RATEMAP_AFTER = 10000; //clean the rateMap every xxxx requests - - private static Object _rateMapLock = new Object(); - - public void ProcessRequest(HttpContext context) { - HttpResponse response = context.Response; - if (context.Request.Url.Query.Length < 1) - { - string errorMsg = "No URL specified"; - log(TraceLevel.Error, errorMsg); - sendErrorResponse(context.Response, null, errorMsg, System.Net.HttpStatusCode.BadRequest); - return; - } - - string uri = context.Request.Url.Query.Substring(1); - - //if url is encoded, decode it. - if (uri.StartsWith("http%3a%2f%2f", StringComparison.InvariantCultureIgnoreCase) || uri.StartsWith("https%3a%2f%2f", StringComparison.InvariantCultureIgnoreCase)) - uri = HttpUtility.UrlDecode(uri); - - log(TraceLevel.Info, uri); - ServerUrl serverUrl; - bool passThrough = false; - try { - serverUrl = getConfig().GetConfigServerUrl(uri); - passThrough = serverUrl == null; - } - //if XML couldn't be parsed - catch (InvalidOperationException ex) { - - string errorMsg = ex.InnerException.Message + " " + uri; - log(TraceLevel.Error, errorMsg); - sendErrorResponse(context.Response, null, errorMsg, System.Net.HttpStatusCode.InternalServerError); - return; - } - //if mustMatch was set to true and URL wasn't in the list - catch (ArgumentException ex) { - string errorMsg = ex.Message + " " + uri; - log(TraceLevel.Error, errorMsg); - sendErrorResponse(context.Response, null, errorMsg, System.Net.HttpStatusCode.Forbidden); - return; - } - //use actual request header instead of a placeholder, if present - if (context.Request.Headers["referer"] != null) - PROXY_REFERER = context.Request.Headers["referer"]; - - //referer - //check against the list of referers if they have been specified in the proxy.config - String[] allowedReferersArray = ProxyConfig.GetAllowedReferersArray(); - if (allowedReferersArray != null && allowedReferersArray.Length > 0) - { - bool allowed = false; - string requestReferer = context.Request.Headers["referer"]; - - foreach (var referer in allowedReferersArray) - { - if ((allowedReferersArray.Length == 1) && referer == String.Empty) - break; - - if (requestReferer != null && requestReferer != String.Empty && (ProxyConfig.isUrlPrefixMatch(referer, requestReferer)) || referer == "*") - { - allowed = true; - break; - } - } - - if (!allowed) - { - string errorMsg = "Proxy is being used from an unsupported referer: " + context.Request.Headers["referer"]; - log(TraceLevel.Error, errorMsg); - sendErrorResponse(context.Response, null, errorMsg, System.Net.HttpStatusCode.Forbidden); - return; - } - } - - //Throttling: checking the rate limit coming from particular client IP - if (!passThrough && serverUrl.RateLimit > -1) { - lock (_rateMapLock) - { - ConcurrentDictionary ratemap = (ConcurrentDictionary)context.Application["rateMap"]; - if (ratemap == null) - { - ratemap = new ConcurrentDictionary(); - context.Application["rateMap"] = ratemap; - context.Application["rateMap_cleanup_counter"] = 0; - } - string key = "[" + serverUrl.Url + "]x[" + context.Request.UserHostAddress + "]"; - RateMeter rate; - if (!ratemap.TryGetValue(key, out rate)) - { - rate = new RateMeter(serverUrl.RateLimit, serverUrl.RateLimitPeriod); - ratemap.TryAdd(key, rate); - } - if (!rate.click()) - { - log(TraceLevel.Warning, " Pair " + key + " is throttled to " + serverUrl.RateLimit + " requests per " + serverUrl.RateLimitPeriod + " minute(s). Come back later."); - sendErrorResponse(context.Response, "This is a metered resource, number of requests have exceeded the rate limit interval.", "Unable to proxy request for requested resource", System.Net.HttpStatusCode.PaymentRequired); - return; - } - - //making sure the rateMap gets periodically cleaned up so it does not grow uncontrollably - int cnt = (int)context.Application["rateMap_cleanup_counter"]; - cnt++; - if (cnt >= CLEAN_RATEMAP_AFTER) - { - cnt = 0; - cleanUpRatemap(ratemap); - } - context.Application["rateMap_cleanup_counter"] = cnt; - } - } - - //readying body (if any) of POST request - byte[] postBody = readRequestPostBody(context); - string post = System.Text.Encoding.UTF8.GetString(postBody); - - System.Net.NetworkCredential credentials = null; - string requestUri = uri; - bool hasClientToken = false; - string token = string.Empty; - string tokenParamName = null; - - if (!passThrough && serverUrl.Domain != null) - { - credentials = new System.Net.NetworkCredential(serverUrl.Username, serverUrl.Password, serverUrl.Domain); - } - else - { - //if token comes with client request, it takes precedence over token or credentials stored in configuration - hasClientToken = uri.Contains("?token=") || uri.Contains("&token=") || post.Contains("?token=") || post.Contains("&token="); - - if (!passThrough && !hasClientToken) - { - // Get new token and append to the request. - // But first, look up in the application scope, maybe it's already there: - token = (String)context.Application["token_for_" + serverUrl.Url]; - bool tokenIsInApplicationScope = !String.IsNullOrEmpty(token); - - //if still no token, let's see if there is an access token or if are credentials stored in configuration which we can use to obtain new token - if (!tokenIsInApplicationScope) - { - token = serverUrl.AccessToken; - if (String.IsNullOrEmpty(token)) - token = getNewTokenIfCredentialsAreSpecified(serverUrl, uri); - } - - if (!String.IsNullOrEmpty(token) && !tokenIsInApplicationScope) - { - //storing the token in Application scope, to do not waste time on requesting new one untill it expires or the app is restarted. - context.Application.Lock(); - context.Application["token_for_" + serverUrl.Url] = token; - context.Application.UnLock(); - } - } - - //name by which token parameter is passed (if url actually came from the list) - tokenParamName = serverUrl != null ? serverUrl.TokenParamName : null; - - if (String.IsNullOrEmpty(tokenParamName)) - tokenParamName = "token"; - - requestUri = addTokenToUri(uri, token, tokenParamName); - } - - - - //forwarding original request - System.Net.WebResponse serverResponse = null; - try { - serverResponse = forwardToServer(context, requestUri, postBody, credentials); - } catch (System.Net.WebException webExc) { - - string errorMsg = webExc.Message + " " + uri; - log(TraceLevel.Error, errorMsg); - - if (webExc.Response != null) - { - copyHeaders(webExc.Response as System.Net.HttpWebResponse, context.Response); - - using (Stream responseStream = webExc.Response.GetResponseStream()) - { - byte[] bytes = new byte[32768]; - int bytesRead = 0; - - while ((bytesRead = responseStream.Read(bytes, 0, bytes.Length)) > 0) - { - responseStream.Write(bytes, 0, bytesRead); - } - - context.Response.StatusCode = (int)(webExc.Response as System.Net.HttpWebResponse).StatusCode; - context.Response.OutputStream.Write(bytes, 0, bytes.Length); - } - } - else - { - System.Net.HttpStatusCode statusCode = System.Net.HttpStatusCode.InternalServerError; - sendErrorResponse(context.Response, null, errorMsg, statusCode); - } - return; - } - - if (passThrough || string.IsNullOrEmpty(token) || hasClientToken) - //if token is not required or provided by the client, just fetch the response as is: - fetchAndPassBackToClient(serverResponse, response, true); - else { - //credentials for secured service have come from configuration file: - //it means that the proxy is responsible for making sure they were properly applied: - - //first attempt to send the request: - bool tokenRequired = fetchAndPassBackToClient(serverResponse, response, false); - - - //checking if previously used token has expired and needs to be renewed - if (tokenRequired) { - log(TraceLevel.Info, "Renewing token and trying again."); - //server returned error - potential cause: token has expired. - //we'll do second attempt to call the server with renewed token: - token = getNewTokenIfCredentialsAreSpecified(serverUrl, uri); - serverResponse = forwardToServer(context, addTokenToUri(uri, token, tokenParamName), postBody); - - //storing the token in Application scope, to do not waste time on requesting new one untill it expires or the app is restarted. - context.Application.Lock(); - context.Application["token_for_" + serverUrl.Url] = token; - context.Application.UnLock(); - - fetchAndPassBackToClient(serverResponse, response, true); - } - } - response.End(); - } - - public bool IsReusable { - get { return true; } - } - -/** -* Private -*/ - private byte[] readRequestPostBody(HttpContext context) { - if (context.Request.InputStream.Length > 0) { - byte[] bytes = new byte[context.Request.InputStream.Length]; - context.Request.InputStream.Read(bytes, 0, (int)context.Request.InputStream.Length); - return bytes; - } - return new byte[0]; - } - - private System.Net.WebResponse forwardToServer(HttpContext context, string uri, byte[] postBody, System.Net.NetworkCredential credentials = null) - { - return - postBody.Length > 0? - doHTTPRequest(uri, postBody, "POST", context.Request.Headers["referer"], context.Request.ContentType, credentials): - doHTTPRequest(uri, context.Request.HttpMethod, credentials); - } - - /// - /// Attempts to copy all headers from the fromResponse to the the toResponse. - /// - /// The response that we are copying the headers from - /// The response that we are copying the headers to - private void copyHeaders(System.Net.WebResponse fromResponse, HttpResponse toResponse) - { - foreach (var headerKey in fromResponse.Headers.AllKeys) - { - switch (headerKey.ToLower()) - { - case "content-type": - case "transfer-encoding": - continue; - default: - toResponse.AddHeader(headerKey, fromResponse.Headers[headerKey]); - break; - } - } - toResponse.ContentType = fromResponse.ContentType; - } - - private bool fetchAndPassBackToClient(System.Net.WebResponse serverResponse, HttpResponse clientResponse, bool ignoreAuthenticationErrors) { - if (serverResponse != null) { - copyHeaders(serverResponse, clientResponse); - using (Stream byteStream = serverResponse.GetResponseStream()) { - // Text response - if (serverResponse.ContentType.Contains("text") || - serverResponse.ContentType.Contains("json") || - serverResponse.ContentType.Contains("xml")) { - using (StreamReader sr = new StreamReader(byteStream)) { - string strResponse = sr.ReadToEnd(); - if ( - !ignoreAuthenticationErrors - && strResponse.IndexOf("{\"error\":{") > -1 - && (strResponse.IndexOf("\"code\":498") > -1 || strResponse.IndexOf("\"code\":499") > -1) - ) - return true; - clientResponse.Write(strResponse); - } - } else { - // Binary response (image, lyr file, other binary file) - - // Tell client not to cache the image since it's dynamic - clientResponse.CacheControl = "no-cache"; - byte[] buffer = new byte[32768]; - int read; - while ((read = byteStream.Read(buffer, 0, buffer.Length)) > 0) - { - clientResponse.OutputStream.Write(buffer, 0, read); - } - clientResponse.OutputStream.Close(); - } - serverResponse.Close(); - } - } - return false; - } - - private System.Net.WebResponse doHTTPRequest(string uri, string method, System.Net.NetworkCredential credentials = null) - { - byte[] bytes = null; - String contentType = null; - log(TraceLevel.Info, "Sending request!"); - - if (method.Equals("POST")) - { - String[] uriArray = uri.Split('?'); - - if (uriArray.Length > 1) - { - contentType = "application/x-www-form-urlencoded"; - String queryString = uriArray[1]; - - bytes = System.Text.Encoding.UTF8.GetBytes(queryString); - } - } - - return doHTTPRequest(uri, bytes, method, PROXY_REFERER, contentType, credentials); - } - - private System.Net.WebResponse doHTTPRequest(string uri, byte[] bytes, string method, string referer, string contentType, System.Net.NetworkCredential credentials = null) - { - System.Net.HttpWebRequest req = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(uri); - req.ServicePoint.Expect100Continue = false; - req.Referer = referer; - req.Method = method; - - if (credentials != null) - req.Credentials = credentials; - - if (bytes != null && bytes.Length > 0 || method == "POST") { - req.Method = "POST"; - req.ContentType = string.IsNullOrEmpty(contentType) ? "application/x-www-form-urlencoded" : contentType; - if (bytes != null && bytes.Length > 0) - req.ContentLength = bytes.Length; - using (Stream outputStream = req.GetRequestStream()) { - outputStream.Write(bytes, 0, bytes.Length); - } - } - return req.GetResponse(); - } - - private string webResponseToString(System.Net.WebResponse serverResponse) { - using (Stream byteStream = serverResponse.GetResponseStream()) { - using (StreamReader sr = new StreamReader(byteStream)) { - string strResponse = sr.ReadToEnd(); - return strResponse; - } - } - } - - private string getNewTokenIfCredentialsAreSpecified(ServerUrl su, string reqUrl) { - string token = ""; - string infoUrl = ""; - - bool isUserLogin = !String.IsNullOrEmpty(su.Username) && !String.IsNullOrEmpty(su.Password); - bool isAppLogin = !String.IsNullOrEmpty(su.ClientId) && !String.IsNullOrEmpty(su.ClientSecret); - if (isUserLogin || isAppLogin) { - log(TraceLevel.Info, "Matching credentials found in configuration file. OAuth 2.0 mode: " + isAppLogin); - if (isAppLogin) { - //OAuth 2.0 mode authentication - //"App Login" - authenticating using client_id and client_secret stored in config - su.OAuth2Endpoint = string.IsNullOrEmpty(su.OAuth2Endpoint) ? DEFAULT_OAUTH : su.OAuth2Endpoint; - if (su.OAuth2Endpoint[su.OAuth2Endpoint.Length - 1] != '/') - su.OAuth2Endpoint += "/"; - log(TraceLevel.Info, "Service is secured by " + su.OAuth2Endpoint + ": getting new token..."); - string uri = su.OAuth2Endpoint + "token?client_id=" + su.ClientId + "&client_secret=" + su.ClientSecret + "&grant_type=client_credentials&f=json"; - string tokenResponse = webResponseToString(doHTTPRequest(uri, "POST")); - token = extractToken(tokenResponse, "token"); - if (!string.IsNullOrEmpty(token)) - token = exchangePortalTokenForServerToken(token, su); - } else { - //standalone ArcGIS Server/ArcGIS Online token-based authentication - - //if a request is already being made to generate a token, just let it go - if (reqUrl.ToLower().Contains("/generatetoken")) { - string tokenResponse = webResponseToString(doHTTPRequest(reqUrl, "POST")); - token = extractToken(tokenResponse, "token"); - return token; - } - - //lets look for '/rest/' in the requested URL (could be 'rest/services', 'rest/community'...) - if (reqUrl.ToLower().Contains("/rest/")) - infoUrl = reqUrl.Substring(0, reqUrl.IndexOf("/rest/", StringComparison.OrdinalIgnoreCase)); - - //if we don't find 'rest', lets look for the portal specific 'sharing' instead - else if (reqUrl.ToLower().Contains("/sharing/")) { - infoUrl = reqUrl.Substring(0, reqUrl.IndexOf("/sharing/", StringComparison.OrdinalIgnoreCase)); - infoUrl = infoUrl + "/sharing"; - } - else - throw new ApplicationException("Unable to determine the correct URL to request a token to access private resources"); - - if (infoUrl != "") { - log(TraceLevel.Info," Querying security endpoint..."); - infoUrl += "/rest/info?f=json"; - //lets send a request to try and determine the URL of a token generator - string infoResponse = webResponseToString(doHTTPRequest(infoUrl, "GET")); - String tokenServiceUri = getJsonValue(infoResponse, "tokenServicesUrl"); - if (string.IsNullOrEmpty(tokenServiceUri)) - tokenServiceUri = getJsonValue(infoResponse, "tokenServiceUrl"); - if (tokenServiceUri != "") { - log(TraceLevel.Info," Service is secured by " + tokenServiceUri + ": getting new token..."); - string uri = tokenServiceUri + "?f=json&request=getToken&referer=" + PROXY_REFERER + "&expiration=60&username=" + su.Username + "&password=" + su.Password; - string tokenResponse = webResponseToString(doHTTPRequest(uri, "POST")); - token = extractToken(tokenResponse, "token"); - } - } - - - } - } - return token; - } - - private string exchangePortalTokenForServerToken(string portalToken, ServerUrl su) { - //ideally, we should POST the token request - log(TraceLevel.Info," Exchanging Portal token for Server-specific token for " + su.Url + "..."); - string uri = su.OAuth2Endpoint.Substring(0, su.OAuth2Endpoint.IndexOf("/oauth2/", StringComparison.OrdinalIgnoreCase)) + - "/generateToken?token=" + portalToken + "&serverURL=" + su.Url + "&f=json"; - string tokenResponse = webResponseToString(doHTTPRequest(uri, "GET")); - return extractToken(tokenResponse, "token"); - } - - private static void sendErrorResponse(HttpResponse response, String errorDetails, String errorMessage, System.Net.HttpStatusCode errorCode) - { - String message = string.Format("{{error: {{code: {0},message:\"{1}\"", (int)errorCode, errorMessage); - if (!string.IsNullOrEmpty(errorDetails)) - message += string.Format(",details:[message:\"{0}\"]", errorDetails); - message += "}}"; - response.StatusCode = (int)errorCode; - //this displays our customized error messages instead of IIS's custom errors - response.TrySkipIisCustomErrors = true; - response.Write(message); - response.Flush(); - } - - private static string getClientIp(HttpRequest request) - { - if (request == null) - return null; - string remoteAddr = request.ServerVariables["HTTP_X_FORWARDED_FOR"]; - if (string.IsNullOrWhiteSpace(remoteAddr)) - { - remoteAddr = request.ServerVariables["REMOTE_ADDR"]; - } - else - { - // the HTTP_X_FORWARDED_FOR may contain an array of IP, this can happen if you connect through a proxy. - string[] ipRange = remoteAddr.Split(','); - remoteAddr = ipRange[ipRange.Length - 1]; - } - return remoteAddr; - } - - private string addTokenToUri(string uri, string token, string tokenParamName) { - if (!String.IsNullOrEmpty(token)) - uri += uri.Contains("?")? "&" + tokenParamName + "=" + token : "?" + tokenParamName + "=" + token; - return uri; - } - - private string extractToken(string tokenResponse, string key) { - string token = getJsonValue(tokenResponse, key); - if (string.IsNullOrEmpty(token)) - log(TraceLevel.Error," Token cannot be obtained: " + tokenResponse); - else - log(TraceLevel.Info," Token obtained: " + token); - return token; - } - - private string getJsonValue(string text, string key) { - int i = text.IndexOf(key); - String value = ""; - if (i > -1) { - value = text.Substring(text.IndexOf(':', i) + 1).Trim(); - value = value.Length > 0 && value[0] == '"' ? - value.Substring(1, value.IndexOf('"', 1) - 1): - value = value.Substring(0, Math.Max(0, Math.Min(Math.Min(value.IndexOf(","), value.IndexOf("]")), value.IndexOf("}")))); - } - return value; - } - - private void cleanUpRatemap(ConcurrentDictionary ratemap) { - foreach (string key in ratemap.Keys){ - RateMeter rate = ratemap[key]; - if (rate.canBeCleaned()) - ratemap.TryRemove(key, out rate); - } - } - -/** -* Static -*/ - private static ProxyConfig getConfig() { - ProxyConfig config = ProxyConfig.GetCurrentConfig(); - if (config != null) - return config; - else - throw new ApplicationException("The proxy configuration file cannot be found, or is not readable."); - } - - //writing Log file - private static void log(TraceLevel logLevel, string msg) { - string logMessage = string.Format("{0} {1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), msg); - if (TraceLevel.Error == logLevel) - { - Trace.TraceError(logMessage); - logMessageToFile(logMessage); - } - else if (TraceLevel.Warning == logLevel) - { - Trace.TraceWarning(logMessage); - logMessageToFile(logMessage); - } - else - { - Trace.TraceInformation(logMessage); - logMessageToFile(logMessage); - } - } - - private static object _lockobject = new object(); - - private static void logMessageToFile(String message) - { - //Only log messages to disk if logFile has value in configuration, otherwise log nothing. - ProxyConfig config = ProxyConfig.GetCurrentConfig(); - if (config.LogFile != null) - { - string log = config.LogFile; - if (!log.Contains("\\") || log.Contains(".\\")) - { - if (log.Contains(".\\")) //If this type of relative pathing .\log.txt - { - log = log.Replace(".\\", ""); - } - string configDirectory = HttpContext.Current.Server.MapPath("proxy.config"); //Cannot use System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath b/ config may be in a child directory - string path = configDirectory.Replace("proxy.config",""); - log = path + log; - } - - lock(_lockobject) { - using (StreamWriter sw = File.AppendText(log)) - { - sw.WriteLine(message); - } - } - } - } -} - - -[XmlRoot("ProxyConfig")] -public class ProxyConfig -{ - private static object _lockobject = new object(); - public static ProxyConfig LoadProxyConfig(string fileName) { - ProxyConfig config = null; - lock (_lockobject) { - if (System.IO.File.Exists(fileName)) { - XmlSerializer reader = new XmlSerializer(typeof(ProxyConfig)); - using (System.IO.StreamReader file = new System.IO.StreamReader(fileName)) { - try { - config = (ProxyConfig)reader.Deserialize(file); - } - catch (Exception ex) { - throw ex; - } - } - } - } - return config; - } - - public static ProxyConfig GetCurrentConfig() { - ProxyConfig config = HttpRuntime.Cache["proxyConfig"] as ProxyConfig; - if (config == null) { - string fileName = HttpContext.Current.Server.MapPath("proxy.config"); - config = LoadProxyConfig(fileName); - if (config != null) { - CacheDependency dep = new CacheDependency(fileName); - HttpRuntime.Cache.Insert("proxyConfig", config, dep); - } - } - return config; - } - - //referer - //create an array with valid referers using the allowedReferers String that is defined in the proxy.config - public static String[] GetAllowedReferersArray() - { - if (allowedReferers == null) - return null; - - return allowedReferers.Split(','); - } - - //referer - //check if URL starts with prefix... - public static bool isUrlPrefixMatch(String prefix, String uri) - { - - return uri.ToLower().StartsWith(prefix.ToLower()) || - uri.ToLower().Replace("https://", "http://").StartsWith(prefix.ToLower()) || - uri.ToLower().Substring(uri.IndexOf("//")).StartsWith(prefix.ToLower()); - } - - ServerUrl[] serverUrls; - public String logFile; - bool mustMatch; - //referer - static String allowedReferers; - - [XmlArray("serverUrls")] - [XmlArrayItem("serverUrl")] - public ServerUrl[] ServerUrls { - get { return this.serverUrls; } - set - { - this.serverUrls = value; - } - } - [XmlAttribute("mustMatch")] - public bool MustMatch { - get { return mustMatch; } - set - { mustMatch = value; } - } - - //logFile - [XmlAttribute("logFile")] - public String LogFile - { - get { return logFile; } - set - { logFile = value; } - } - - - //referer - [XmlAttribute("allowedReferers")] - public string AllowedReferers - { - get { return allowedReferers; } - set - { - allowedReferers = value; - } - } - - public ServerUrl GetConfigServerUrl(string uri) { - //split both request and proxy.config urls and compare them - string[] uriParts = uri.Split(new char[] {'/','?'}, StringSplitOptions.RemoveEmptyEntries); - string[] configUriParts = new string[] {}; - - foreach (ServerUrl su in serverUrls) { - //if a relative path is specified in the proxy.config, append what's in the request itself - if (!su.Url.StartsWith("http")) - su.Url = su.Url.Insert(0, uriParts[0]); - - configUriParts = su.Url.Split(new char[] { '/','?' }, StringSplitOptions.RemoveEmptyEntries); - - //if the request has less parts than the config, don't allow - if (configUriParts.Length > uriParts.Length) continue; - - int i = 0; - for (i = 0; i < configUriParts.Length; i++) { - - if (!configUriParts[i].ToLower().Equals(uriParts[i].ToLower())) break; - } - if (i == configUriParts.Length) { - //if the urls don't match exactly, and the individual matchAll tag is 'false', don't allow - if (configUriParts.Length == uriParts.Length || su.MatchAll) - return su; - } - } - - if (mustMatch) - throw new ArgumentException("Proxy is being used for an unsupported service:"); - - return null; - } - - -} - -public class ServerUrl { - string url; - bool matchAll; - string oauth2Endpoint; - string domain; - string username; - string password; - string clientId; - string clientSecret; - string accessToken; - string tokenParamName; - string rateLimit; - string rateLimitPeriod; - - [XmlAttribute("url")] - public string Url { - get { return url; } - set { url = value; } - } - [XmlAttribute("matchAll")] - public bool MatchAll { - get { return matchAll; } - set { matchAll = value; } - } - [XmlAttribute("oauth2Endpoint")] - public string OAuth2Endpoint { - get { return oauth2Endpoint; } - set { oauth2Endpoint = value; } - } - [XmlAttribute("domain")] - public string Domain - { - get { return domain; } - set { domain = value; } - } - [XmlAttribute("username")] - public string Username { - get { return username; } - set { username = value; } - } - [XmlAttribute("password")] - public string Password { - get { return password; } - set { password = value; } - } - [XmlAttribute("clientId")] - public string ClientId { - get { return clientId; } - set { clientId = value; } - } - [XmlAttribute("clientSecret")] - public string ClientSecret { - get { return clientSecret; } - set { clientSecret = value; } - } - [XmlAttribute("accessToken")] - public string AccessToken { - get { return accessToken; } - set { accessToken = value; } - } - [XmlAttribute("tokenParamName")] - public string TokenParamName { - get { return tokenParamName; } - set { tokenParamName = value; } - } - [XmlAttribute("rateLimit")] - public int RateLimit { - get { return string.IsNullOrEmpty(rateLimit)? -1 : int.Parse(rateLimit); } - set { rateLimit = value.ToString(); } - } - [XmlAttribute("rateLimitPeriod")] - public int RateLimitPeriod { - get { return string.IsNullOrEmpty(rateLimitPeriod)? 60 : int.Parse(rateLimitPeriod); } - set { rateLimitPeriod = value.ToString(); } - } -} diff --git a/viewer/proxy/proxy.config b/viewer/proxy/proxy.config deleted file mode 100755 index ef689f898..000000000 --- a/viewer/proxy/proxy.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - diff --git a/viewer/proxy/proxy.xsd b/viewer/proxy/proxy.xsd deleted file mode 100755 index d6c057fa8..000000000 --- a/viewer/proxy/proxy.xsd +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/viewer/proxy/readme.md b/viewer/proxy/readme.md deleted file mode 100644 index 630a8993d..000000000 --- a/viewer/proxy/readme.md +++ /dev/null @@ -1,7 +0,0 @@ -# AGS Proxy page help - -For full info please read here: -[https://developers.arcgis.com/javascript/jshelp/ags_proxy.html](https://developers.arcgis.com/javascript/jshelp/ags_proxy.html) - -You will more than likely need a proxy page for printing and other large cross domain requests. -There are diffrent flavors (.net, jsp, php) of the proxy page depending on your server side technology. See the above link for full details. \ No newline at end of file
+ ${i18n.preserve}: - ${i18n.mapScale}   + ${i18n.mapScale}
${i18n.mapExtent}