├── .gitignore ├── .babelrc ├── example ├── screenshot.png ├── img │ ├── markerActive.png │ └── markerDefault.png ├── index.html └── example.js ├── .editorconfig ├── .travis.yml ├── .eslintrc ├── license.md ├── webpack.config.js ├── logo.svg ├── package.json ├── readme.md ├── src └── easygooglemaps.js └── dist ├── easygooglemaps.min.js └── easygooglemaps.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | npm-debug.log 4 | report.html 5 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"], 3 | "plugins": ["add-module-exports"] 4 | } 5 | -------------------------------------------------------------------------------- /example/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver/EasyGoogleMaps/HEAD/example/screenshot.png -------------------------------------------------------------------------------- /example/img/markerActive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver/EasyGoogleMaps/HEAD/example/img/markerActive.png -------------------------------------------------------------------------------- /example/img/markerDefault.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver/EasyGoogleMaps/HEAD/example/img/markerDefault.png -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | cache: 4 | directories: 5 | - node_modules 6 | notifications: 7 | email: false 8 | node_js: 9 | - 'stable' 10 | - v4 11 | - '0.12' 12 | branches: 13 | except: 14 | - "/^v\\d+\\.\\d+\\.\\d+$/" 15 | after_script: 16 | - npm run coveralls 17 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "plugins": [ 4 | "babel" 5 | ], 6 | "rules": { 7 | "strict": 0, 8 | "babel/generator-star-spacing": 1, 9 | "babel/new-cap": 1, 10 | "babel/object-shorthand": 1, 11 | "babel/arrow-parens": 1, 12 | "array-bracket-spacing": [2, "never"], 13 | "block-scoped-var": 2, 14 | "brace-style": [2, "1tbs"], 15 | "camelcase": 1, 16 | "curly": 2, 17 | "eol-last": 2, 18 | "eqeqeq": [2, "smart"], 19 | "indent": [2, 2, { "SwitchCase": 1 }], 20 | "max-depth": [1, 3], 21 | "max-len": [1, 80], 22 | "max-statements": [1, 15], 23 | "new-cap": 1, 24 | "no-extend-native": 2, 25 | "no-mixed-spaces-and-tabs": 2, 26 | "no-trailing-spaces": 2, 27 | "no-unused-vars": 1, 28 | "no-use-before-define": [2, "nofunc"], 29 | "object-curly-spacing": [1, "always"], 30 | "quotes": [2, "single", "avoid-escape"], 31 | "semi": [2, "always"], 32 | "space-after-keywords": [2, "always"], 33 | "space-unary-ops": 2 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var minimize = process.argv.indexOf('--no-minimize') === -1 ? true : false; 3 | var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 4 | var plugins = minimize ? [ 5 | new webpack.optimize.UglifyJsPlugin({ 6 | minimize: true, 7 | compress: { 8 | drop_console: true 9 | }, 10 | }), 11 | new webpack.optimize.MinChunkSizePlugin({minChunkSize: '100000'}), 12 | new BundleAnalyzerPlugin( { 13 | analyzerMode: 'static', 14 | analyzerPort: 4000, 15 | openAnalyzer: false 16 | } 17 | ) 18 | ] : [ 19 | new webpack.optimize.MinChunkSizePlugin({minChunkSize: '100000'}) 20 | ]; 21 | 22 | module.exports = { 23 | node: { 24 | console: 'empty', 25 | fs: 'empty', 26 | net: 'empty', 27 | tls: 'empty' 28 | }, 29 | entry: { 30 | 'dist/easygooglemaps':'./src/easygooglemaps.js' 31 | }, 32 | output: { 33 | path: './', 34 | filename: minimize ? '[name].min.js' : '[name].js', 35 | libraryTarget: 'umd', 36 | library: 'EasyGoogleMaps' 37 | }, 38 | module: { 39 | loaders: [{ 40 | test: /\.js?$/, 41 | exclude: /(node_modules|bower_components)/, 42 | loader: 'babel' 43 | },{ 44 | test: /\.json$/, 45 | loader: 'json' 46 | }] 47 | }, 48 | plugins: plugins 49 | }; 50 | -------------------------------------------------------------------------------- /logo.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 8 | 9 | 12 | 13 | 14 | 15 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "easygooglemaps", 3 | "version": "1.2.3", 4 | "description": "Simple layer over Google Maps API for creating maps with markers and controlled balloons.", 5 | "main": "dist/easygooglemaps.js", 6 | "scripts": { 7 | "precommit": "npm run build", 8 | "build": "rimraf dist && webpack --no-minimize && webpack", 9 | "watch": "rimraf dist && webpack --watch", 10 | "coverage": "babel-node node_modules/isparta/bin/isparta cover node_modules/mocha/bin/_mocha --report lcovonly -- -R spec", 11 | "coveralls": "npm run coverage && coveralls < coverage/lcov.info && rimraf coverage", 12 | "test": "npm run test-server && npm run test-browser", 13 | "test-server": "mocha test/server --recursive --bail --require babel-core/register mocha.config.js", 14 | "test-browser": "karma start --single-run", 15 | "tdd": "npm run test-server -- --watch", 16 | "tdd-browser": "karma start" 17 | }, 18 | "repository": "coderiver/easygooglemaps", 19 | "keywords": [ 20 | "google maps", 21 | "markers", 22 | "js", 23 | "easy", 24 | "infobox", 25 | "baloons" 26 | ], 27 | "files": [ 28 | "dist", 29 | "src" 30 | ], 31 | "devDependencies": { 32 | "babel-core": "^6.4.5", 33 | "babel-eslint": "^4.1.4", 34 | "babel-loader": "^6.2.2", 35 | "babel-plugin-add-module-exports": "^0.1.2", 36 | "babel-preset-es2015": "^6.3.13", 37 | "eslint": "^1.4.1", 38 | "eslint-plugin-babel": "^3.1.0", 39 | "husky": "^0.10.1", 40 | "mocha-lcov-reporter": "^1.0.0", 41 | "rimraf": "^2.4.3", 42 | "webpack": "^1.12.2", 43 | "webpack-bundle-analyzer": "^2.3.0", 44 | "json-loader": "^0.5.4" 45 | }, 46 | "author": { 47 | "name": "Valentin Dorosh", 48 | "email": "wh2ts0n9057@gmail.com" 49 | }, 50 | "contributors": [ 51 | { 52 | "name": "Yuri Artiukh", 53 | "email": "akella.a@gmail.com", 54 | "url": "http://cssing.org.ua/" 55 | } 56 | ], 57 | "engines": { 58 | "node": ">=0.12.0" 59 | }, 60 | "license": "MIT", 61 | "dependencies": { 62 | "dot": "^1.1.1", 63 | "google-maps": "^3.2.1", 64 | "google-maps-infobox": "^1.1.14" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | EasyGoogleMaps example 8 | 9 | 10 | 11 | 12 | 90 | 91 | 92 | 93 | 94 |
95 | 96 |
97 | 98 | 99 | 100 | 101 | 102 |
103 | 104 | 105 | 106 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | [![npm version](https://badge.fury.io/js/easygooglemaps.svg)](https://badge.fury.io/js/easygooglemaps) 3 | [![Dependency Status][depstat-image]][depstat-url] 4 | 5 | 6 | > Simple layer over Google Maps API to create expandable baloons(infoboxes) on the map. [See example](https://coderiver.github.io/EasyGoogleMaps/example/index.html). We are tired of google maps syntax, infobox and whatever. Simple and straightforward syntax to do common job like this: 9 | > 10 | > ![Module usage example](https://github.com/coderiver/easygooglemaps/raw/master/example/screenshot.png "Module usage example") 11 | 12 | ## Installation 13 | 14 | ``` 15 | $ npm install --save easygooglemaps 16 | ``` 17 | 18 | ## Usage 19 | ### Webpack 20 | ```js 21 | var EasyGoogleMaps = require('easygooglemaps'); 22 | // run module here 23 | ``` 24 | ### Old school files way ([example.html](https://coderiver.github.io/EasyGoogleMaps/example/index.html)): 25 | ```html 26 | 27 | 28 | ``` 29 | ## Running 30 | ```js 31 | var MyMap = new EasyGoogleMaps(_options_); 32 | // options reference in next section 33 | 34 | MyMap.init(); 35 | ``` 36 | 37 | 38 | #### Parameters (_options_) 39 | ```js 40 | { 41 | // map options 42 | map: { 43 | APIKEY: 'YOUR_GOOGLEMAPS_API_KEY', 44 | container: '.js-map', // DOM element, where to put map 45 | options: { 46 | center: {lat: -34.097, lng: 150.644}, 47 | zoom: 8 48 | } 49 | }, 50 | 51 | // baloon specific options 52 | infobox: { 53 | class: 'awesome-infobox', 54 | template: '#infobox', // html template for baloon 55 | closeButton: '.js-infobox-close', 56 | onlyOneBox: true, // single baloon visible 57 | // baloon relative to marker position 58 | position: { 59 | x: "left", 60 | y: "center" 61 | } 62 | }, 63 | 64 | // Array of data (markers,baloons,infoboxes,whatever) to put on the map 65 | // Might be added at any time by .add method described below 66 | markers: { 67 | items: [ 68 | { 69 | "content": { 70 | // this is {{=baloon.title}} in html template 71 | "title": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolore, consequatur." 72 | }, 73 | "marker": { 74 | "position": { 75 | "lat": -34.397, 76 | "lng": 150.644 77 | }, 78 | "icon": { 79 | "default": "img/markerDefault.png", 80 | "active": "img/markerActive.png", 81 | // for retina icon should be 40x60 pixels 82 | "size": { 83 | "x": 20, 84 | "y": 30 85 | }, 86 | "centering": { 87 | "x": 10, 88 | "y": 30 89 | } 90 | } 91 | } 92 | } 93 | ] 94 | } 95 | } 96 | ``` 97 | And also HTML template ([doT template engine](http://olado.github.io/doT/index.html)) for infobox should be specified: 98 | ```html 99 | 107 | ``` 108 | 109 | ## Methods 110 | ### Load (callback) 111 | ```js 112 | MyMap.onload(function() { 113 | // show map with animation, once it is loaded 114 | }); 115 | ``` 116 | ### Add marker 117 | ```js 118 | // this method also accepts array of markers 119 | MyMap.add({ 120 | "content": { 121 | "title": "Lorem ipsum" 122 | }, 123 | "marker": { 124 | "id": 5, // optional, only if you need to show-hide it later 125 | "position": { 126 | "lat": -34.397, 127 | "lng": 152.244 128 | }, 129 | "icon": { 130 | "default": "img/markerDefault.png", 131 | "active": "img/markerActive.png", // optional 132 | "size": { 133 | "x": 41, 134 | "y": 58 135 | }, 136 | "centering": { 137 | "x": 20, 138 | "y": 58 139 | } 140 | } 141 | } 142 | }); 143 | ``` 144 | ### Show-Hide by id 145 | ```js 146 | MyMap.show(2); // shows all markers (one or many) with id equal 2 147 | MyMap.hide(2); // same, but hides 148 | ``` 149 | ### Google Map Object 150 | Though our script wraps most of the use cases with map and infoboxes. You can still do whatever you want, because you have access to original Google Maps API: 151 | ```js 152 | MyMap.realmap; // returns Google Maps map object 153 | ``` 154 | ## Development 155 | - `npm run build` - Build task that generates both minified and non-minified scripts, 156 | - `npm run watch` - watch changes, build only minified version; 157 | 158 | 159 | ## Authors: 160 | Valentin ‘Whats0n’ Dorosh 161 | 162 | Yuri [akella](http://cssing.org.ua) Artiukh 163 | 164 | ## License 165 | MIT © [Coderiver](http://riverco.de) 166 | 167 | [depstat-url]: https://david-dm.org/coderiver/easygooglemaps 168 | [depstat-image]: https://david-dm.org/coderiver/easygooglemaps.svg -------------------------------------------------------------------------------- /example/example.js: -------------------------------------------------------------------------------- 1 | // ======================================= 2 | // ====BASIC SETTINGS===================== 3 | // ======================================= 4 | let map = new EasyGoogleMaps({ 5 | map: { 6 | APIKEY: 'AIzaSyDMWIxCN9ijYRfiH7bmQN-LNRDtoboLZqY', 7 | container: '.js-map', 8 | options: { 9 | center: {lat: -34.097, lng: 150.644}, 10 | zoom: 8 11 | } 12 | }, 13 | 14 | infobox: { 15 | template: '#infobox', 16 | class: 'awesome-infobox', 17 | onlyOneBox: true, 18 | style: { 19 | width: '300px' 20 | }, 21 | position: { 22 | x: "left", 23 | y: "center" 24 | }, 25 | closeButton: '.js-infobox-close' 26 | }, 27 | 28 | markers: { 29 | items: [ 30 | { 31 | "content": { 32 | "title": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolore, consequatur." 33 | }, 34 | "marker": { 35 | "id": 0, 36 | "position": { 37 | "lat": -34.397, 38 | "lng": 150.644 39 | }, 40 | "icon": { 41 | "default": "img/markerDefault.png", 42 | "active": "img/markerActive.png", 43 | "size": { 44 | "x": 41, 45 | "y": 58 46 | }, 47 | "centering": { 48 | "x": 20, 49 | "y": 58 50 | } 51 | } 52 | } 53 | }, 54 | { 55 | "content": { 56 | "title": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolore, consequatur." 57 | }, 58 | "marker": { 59 | "id": 1, 60 | "position": { 61 | "lat": -34.397, 62 | "lng": 150.244 63 | }, 64 | "icon": { 65 | "default": "img/markerDefault.png", 66 | "active": "img/markerActive.png", 67 | "size": { 68 | "x": 41, 69 | "y": 58 70 | }, 71 | "centering": { 72 | "x": 20, 73 | "y": 58 74 | } 75 | } 76 | } 77 | } 78 | ] 79 | } 80 | }); 81 | // ======================================= 82 | // ========INITIATING MAP================= 83 | // ======================================= 84 | map.init(); 85 | 86 | // ======================================= 87 | // ========ADDING ARRAY OF POINTS========= 88 | // ======================================= 89 | map.add([ 90 | { 91 | "content": { 92 | "title": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolore, consequatur." 93 | }, 94 | "marker": { 95 | "id": 2, 96 | "position": { 97 | "lat": -34.397, 98 | "lng": 151.044 99 | }, 100 | "icon": { 101 | "default": "img/markerDefault.png", 102 | "active": "img/markerActive.png", 103 | "size": { 104 | "x": 41, 105 | "y": 58 106 | }, 107 | "centering": { 108 | "x": 20, 109 | "y": 58 110 | } 111 | } 112 | } 113 | }, 114 | { 115 | "content": { 116 | "title": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolore, consequatur." 117 | }, 118 | "marker": { 119 | "id": 3, 120 | "position": { 121 | "lat": -34.397, 122 | "lng": 151.444 123 | }, 124 | "icon": { 125 | "default": "img/markerDefault.png", 126 | "active": "img/markerActive.png", 127 | "size": { 128 | "x": 41, 129 | "y": 58 130 | }, 131 | "centering": { 132 | "x": 20, 133 | "y": 58 134 | } 135 | } 136 | } 137 | } 138 | ]); 139 | 140 | // ======================================= 141 | // ========ADDING ONE POINT=============== 142 | // ======================================= 143 | map.add({ 144 | "content": { 145 | "title": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolore, consequatur." 146 | }, 147 | "marker": { 148 | "id": 4, 149 | "position": { 150 | "lat": -34.397, 151 | "lng": 151.844 152 | }, 153 | "icon": { 154 | "default": "img/markerDefault.png", 155 | "active": "img/markerActive.png", 156 | "size": { 157 | "x": 41, 158 | "y": 58 159 | }, 160 | "centering": { 161 | "x": 20, 162 | "y": 58 163 | } 164 | } 165 | } 166 | }); 167 | 168 | let addOneMarker = document.querySelector('.js-add-one'); 169 | let addSeveralMarker = document.querySelector('.js-add-several'); 170 | 171 | let showMarker = document.querySelector('.js-show'); 172 | let hideMarker = document.querySelector('.js-hide'); 173 | 174 | addOneMarker.addEventListener('click', () => { 175 | // ======================================= 176 | // ====ADDING ONE POINT WITH CLICK======== 177 | // ======================================= 178 | map.add({ 179 | "content": { 180 | "title": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolore, consequatur." 181 | }, 182 | "marker": { 183 | "id": 5, 184 | "position": { 185 | "lat": -34.397, 186 | "lng": 152.244 187 | }, 188 | "icon": { 189 | "default": "img/markerDefault.png", 190 | "active": "img/markerActive.png", 191 | "size": { 192 | "x": 41, 193 | "y": 58 194 | }, 195 | "centering": { 196 | "x": 20, 197 | "y": 58 198 | } 199 | } 200 | } 201 | }); 202 | }, false); 203 | 204 | addSeveralMarker.addEventListener('click', function() { 205 | // ======================================= 206 | // ====ADDING MANY POINTS WITH CLICK====== 207 | // ======================================= 208 | map.add([ 209 | { 210 | "content": { 211 | "title": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolore, consequatur." 212 | }, 213 | "marker": { 214 | "id": 6, 215 | "position": { 216 | "lat": -34.397, 217 | "lng": 152.644 218 | }, 219 | "icon": { 220 | "default": "img/markerDefault.png", 221 | "active": "img/markerActive.png", 222 | "size": { 223 | "x": 41, 224 | "y": 58 225 | }, 226 | "centering": { 227 | "x": 20, 228 | "y": 58 229 | } 230 | } 231 | } 232 | }, 233 | { 234 | "content": { 235 | "title": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolore, consequatur." 236 | }, 237 | "marker": { 238 | "id": 7, 239 | "position": { 240 | "lat": -34.397, 241 | "lng": 153.044 242 | }, 243 | "icon": { 244 | "default": "img/markerDefault.png", 245 | "active": "img/markerActive.png", 246 | "size": { 247 | "x": 41, 248 | "y": 58 249 | }, 250 | "centering": { 251 | "x": 20, 252 | "y": 58 253 | } 254 | } 255 | } 256 | } 257 | ]); 258 | }, false); 259 | 260 | 261 | // ======================================= 262 | // ====SHOW HIDE MARKER=================== 263 | // ======================================= 264 | showMarker.addEventListener('click', function() { 265 | map.show(2); 266 | }, false); 267 | 268 | hideMarker.addEventListener('click', function() { 269 | map.hide(2); 270 | }, false); 271 | 272 | 273 | // ======================================= 274 | // ====ONLOAD EVENT======================= 275 | // ======================================= 276 | 277 | // map.onload(() => { 278 | // alert('loaded'); 279 | // }); 280 | // alert('not loaded'); 281 | -------------------------------------------------------------------------------- /src/easygooglemaps.js: -------------------------------------------------------------------------------- 1 | /** 2 | * EasyGoogleMaps 3 | * Description 4 | * Creates map with expandable markers 5 | * @name EasyGoogleMaps 6 | */ 7 | import GoogleMapsLoader from 'google-maps'; 8 | import dot from 'dot'; 9 | 10 | 11 | export default (function() { 12 | 13 | let INFOBOX = null; 14 | let template = null; 15 | 16 | const utils = { 17 | isString(props) { 18 | return (typeof props == 'string' && props.length); 19 | }, 20 | isObj(props) { 21 | return (props != null && !Array.isArray(props) && typeof props == 'object'); 22 | }, 23 | isArr(props) { 24 | return Array.isArray(props); 25 | }, 26 | isFunc(fn) { 27 | return typeof fn == 'function'; 28 | } 29 | }; 30 | 31 | class Map { 32 | 33 | constructor(props) { 34 | this._props = props || {}; 35 | this._markers = []; 36 | this._infoboxes = []; 37 | this._onLoad = []; 38 | this._isLoaded = false; 39 | this._temporaryStorage = []; 40 | this._defaultWidth = '300px'; 41 | } 42 | 43 | //******************************************* 44 | //******************PUBLIC******************* 45 | //******************************************* 46 | 47 | init() { 48 | let props = this._props; 49 | 50 | GoogleMapsLoader.KEY = props.map.APIKEY; 51 | GoogleMapsLoader.load((google) => { 52 | 53 | require(["google-maps-infobox"], (InfoBox) => { 54 | //set value to the global infobox variable 55 | INFOBOX = InfoBox; 56 | this._initMap(); 57 | 58 | //flag to know when the map and the infobox are loaded 59 | this._isLoaded = true; 60 | 61 | template = utils.isString(props.infobox.template) 62 | ? this._getTemplate() 63 | : null; 64 | 65 | //call onLoadCallbacks 66 | if (this._onLoad.length) this._onLoad.forEach(callback => callback()); 67 | //add markers by method if method was called when map is not loaded 68 | this._addItems(this._temporaryStorage); 69 | this._temporaryStorage = []; 70 | this._closeOnMapClick(); 71 | 72 | //check for morons... 73 | if (!!!props.markers) return; 74 | if (!utils.isObj(props.markers)) return console.error('Data must be an object!!!'); 75 | if (!Object.keys(props.markers).length) return console.error('Data must be a non-empty object!!!'); 76 | 77 | //If you want to get info from some another file using ajax, 78 | //you need set path to the file to property 'url'. 79 | if (props.markers && props.markers.url) { 80 | if (!utils.isString(props.markers) && utils.isString(props.markers.url)) { 81 | this._loadData((items) => { 82 | this._addItems(items); 83 | }); 84 | } 85 | } else if (props.markers && !props.markers.url) { 86 | this._addItems(props.markers.items); 87 | } 88 | }); 89 | 90 | }); 91 | } 92 | 93 | onload(callback) { 94 | if (!utils.isFunc(callback)) return; 95 | this._onLoad.push(callback); 96 | } 97 | 98 | //ADD MARKERS 99 | add(props) { 100 | if (utils.isObj(props)) { 101 | if (!this._isLoaded) { 102 | this._temporaryStorage.push(props); 103 | return; 104 | }; 105 | 106 | this._addItem(props); 107 | return; 108 | } 109 | 110 | if (utils.isArr(props)) { 111 | if (!this._isLoaded) { 112 | this._temporaryStorage = this._temporaryStorage.concat(props); 113 | return; 114 | }; 115 | 116 | this._addItems(props); 117 | return; 118 | } 119 | } 120 | //SHOW MARKER BY ID 121 | show(id) { 122 | let currentID = id; 123 | this._markers.forEach(marker => { 124 | if (!currentID || currentID && marker.id == currentID) return marker.setMap(this._map); 125 | }); 126 | } 127 | //HIDE MARKER BY ID 128 | hide(id) { 129 | let currentID = id; 130 | this._markers.forEach(marker => { 131 | if (!currentID || currentID && marker.id == currentID) return marker.setMap(null); 132 | }); 133 | } 134 | 135 | //******************************************* 136 | //******************PRIVAT******************* 137 | //******************************************* 138 | 139 | _initMap() { 140 | let props = this._props; 141 | this._container = document.querySelector(props.map.container); 142 | this._map = new google.maps.Map(this._container, props.map.options); 143 | this.realmap = this._map; 144 | } 145 | 146 | _loadData(callback) { 147 | let props = this._props; 148 | 149 | let path = this._container.getAttribute(props.markers.url); 150 | let xhr = new XMLHttpRequest(); 151 | 152 | xhr.open('GET', path, true); 153 | xhr.onload = () => { 154 | if (xhr.status != 200) return console.error('ошибочка, data not found'); 155 | callback(JSON.parse(xhr.responseText)); 156 | }; 157 | xhr.send(); 158 | } 159 | 160 | _getTemplate() { 161 | let HTML = document.querySelector(this._props.infobox.template).innerHTML; 162 | dot.templateSettings.varname = 'baloon'; 163 | return dot.template(HTML); 164 | } 165 | 166 | //******************************************* 167 | //*****************ALL ITEMS***************** 168 | //******************************************* 169 | 170 | _addItems(items) { 171 | for (let i = 0; i < items.length; i++) { 172 | this._addItem(items[i]); 173 | } 174 | } 175 | 176 | _addItem(item) { 177 | let markerOptions = item.marker; 178 | let marker = this._createMarker(markerOptions); 179 | 180 | this._markers.push(marker); 181 | 182 | if (template && this._props.infobox) { 183 | let content = item.content; 184 | let compiled = template(content); 185 | let ib = this._createInfoBox(compiled, marker); 186 | 187 | this._infoboxes.push(ib); 188 | //toggle content on click 189 | google.maps.event.addListener(marker, 'click', e => this._toggleInfobox(ib, marker)); 190 | google.maps.event.addListener(ib, 'domready', e => this._addEventOnCloseButton(ib, marker)); 191 | } 192 | } 193 | 194 | _closeOnMapClick() { 195 | if (!this._props.infobox.onlyOneBox) return; 196 | google.maps.event.addListener(this._map, 'click', e => { 197 | this._closeAllInfobox(); 198 | }); 199 | } 200 | 201 | _addEventOnCloseButton(ib, marker) { 202 | let props = this._props; 203 | let infobox = ib.div_; 204 | let buttons = infobox.querySelectorAll(props.infobox.closeButton); 205 | 206 | this._setInfoBoxPosition(ib, infobox); 207 | 208 | Array.prototype.forEach.call(buttons, button => { 209 | button.addEventListener('click', e => { 210 | e.preventDefault(); 211 | this._closeInfobox(ib); 212 | this._closeMarker(marker); 213 | }, false); 214 | }); 215 | } 216 | 217 | //******************************************* 218 | //*************SHOW/CLOSE METHODS************ 219 | //******************************************* 220 | 221 | _closeAllInfobox() { 222 | this._infoboxes.forEach(infobox => this._closeInfobox(infobox)); 223 | this._closeMarkers(); 224 | } 225 | 226 | _closeInfobox(item) { 227 | item.close(); 228 | item.isOpen = false; 229 | } 230 | 231 | _openInfobox(item, marker) { 232 | item.open(this._map, marker); 233 | item.isOpen = true; 234 | } 235 | 236 | _toggleInfobox(item, marker) { 237 | let activeIcon = marker.activeIcon; 238 | let defaultIcon = marker.defaultIcon; 239 | if (!item.isOpen) { 240 | if (this._props.infobox.onlyOneBox) { 241 | this._closeAllInfobox(); 242 | this._closeMarkers(); 243 | } 244 | this._openInfobox(item, marker); 245 | if (!!activeIcon && activeIcon.length) this._toggleMarker(marker, 'activeIcon'); 246 | } else { 247 | this._closeInfobox(item); 248 | if (!!activeIcon && activeIcon.length) this._toggleMarker(marker, 'defaultIcon'); 249 | } 250 | } 251 | 252 | //******************************************* 253 | //******************MARKERS****************** 254 | //******************************************* 255 | 256 | _createMarker(data) { 257 | let icon = data.icon; 258 | let size = icon.size; 259 | let centering = icon.centering || { 260 | x: 0, 261 | y: 0 262 | }; 263 | let iconStyles = { 264 | url: icon.default || '', 265 | scaledSize: new google.maps.Size(size.x, size.y), 266 | anchor: new google.maps.Point(centering.x, centering.y) 267 | }; 268 | 269 | let marker = new google.maps.Marker({ 270 | map: this._map, 271 | position: data.position, 272 | defaultIcon: data.icon.default || '', 273 | activeIcon: data.icon.active || '', 274 | iconSize: size, 275 | iconStyles: iconStyles, 276 | id: data.id 277 | }); 278 | 279 | if (icon.default) marker.setIcon(iconStyles); 280 | 281 | return marker; 282 | } 283 | 284 | _closeMarkers() { 285 | this._markers.forEach(marker => this._closeMarker(marker)); 286 | } 287 | 288 | _closeMarker(marker) { 289 | marker.setIcon(marker.iconStyles); 290 | } 291 | 292 | _toggleMarker(marker, img) { 293 | let icon = JSON.parse(JSON.stringify(marker.iconStyles)); 294 | icon.url = marker[img]; 295 | marker.setIcon(icon) 296 | } 297 | 298 | //******************************************* 299 | //******************INFOBOX****************** 300 | //******************************************* 301 | 302 | _createInfoBox(content, marker) { 303 | let props = this._props.infobox; 304 | 305 | let style = props.style || {}; 306 | let width = style.width || this._defaultWidth; 307 | style.width = width; 308 | 309 | let markerSize = marker.iconSize; 310 | 311 | this._offsetX = markerSize.x; 312 | this._offsetY = markerSize.y; 313 | 314 | return new INFOBOX({ 315 | content: content, 316 | 317 | enableEventPropagation: false, 318 | 319 | //move map to the current box 320 | disableAutoPan: false, 321 | //margins from map borders 322 | infoBoxClearance: new google.maps.Size(10, 10), 323 | 324 | boxClass: props.class || 'infobox', 325 | zIndex: props.zIndex || null, 326 | maxWidth: props.maxWidth || 0, 327 | boxStyle: style, 328 | 329 | //The URL of the image representing the close box. 330 | //Note: The default is the URL for Google's standard close box. 331 | //Set this property to "" if no close box is required. 332 | closeBoxURL: '', 333 | 334 | pane: "floatPane", 335 | 336 | //flag opened or closed 337 | isOpen: false 338 | }); 339 | } 340 | 341 | //POPUP POSITION 342 | _setInfoBoxPosition(infobox, div) { 343 | 344 | //get map popup options 345 | let props = this._props.infobox; 346 | 347 | let width = div.offsetWidth; 348 | let height = div.offsetHeight; 349 | 350 | let position = props.position || {}; 351 | let x = position.x || 'top'; 352 | let y = position.y || 'center'; 353 | 354 | this._positionX = this._getInfoBoxPositionX(x, width, this._offsetX); 355 | this._positionY = this._getInfoBoxPositionY(y, height, this._offsetY); 356 | 357 | infobox.setOptions({ 358 | pixelOffset: new google.maps.Size(this._positionX, this._positionY.offset), 359 | alignBottom: this._positionY.align 360 | }); 361 | } 362 | 363 | _getInfoBoxPositionY(y, height, offset) { 364 | switch (y) { 365 | case "top": 366 | return { 367 | offset: -offset, 368 | align: true 369 | }; 370 | case "center": 371 | return { 372 | offset: -height/2 -offset/2, 373 | align: false 374 | } 375 | } 376 | 377 | return { 378 | offset: 0, 379 | align: false 380 | }; 381 | } 382 | 383 | _getInfoBoxPositionX(x, width, offset) { 384 | switch (x) { 385 | case "left": 386 | return -width - offset/2; 387 | case "right": 388 | return offset/2; 389 | 390 | } 391 | 392 | return -width/2 - offset/2; 393 | } 394 | 395 | //******************************************* 396 | //******************INFOBOX****************** 397 | //******************************************* 398 | 399 | } 400 | 401 | return Map; 402 | 403 | })(); -------------------------------------------------------------------------------- /dist/easygooglemaps.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.EasyGoogleMaps=t():e.EasyGoogleMaps=t()}(this,function(){return function(e){function t(n){if(i[n])return i[n].exports;var o=i[n]={exports:{},id:n,loaded:!1};return e[n].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var i={};return t.m=e,t.c=i,t.p="",t(0)}([function(e,t,i){(function(n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var r=function(){function e(e,t){for(var i=0;i0&&(e+="&libraries="+a.LIBRARIES.join(",")),a.CLIENT&&(e+="&client="+a.CLIENT+"&v="+a.VERSION),a.CHANNEL&&(e+="&channel="+a.CHANNEL),a.LANGUAGE&&(e+="&language="+a.LANGUAGE),a.REGION&&(e+="®ion="+a.REGION),e},a.release=function(l){var d=function(){a.KEY=null,a.LIBRARIES=[],a.CLIENT=null,a.CHANNEL=null,a.LANGUAGE=null,a.REGION=null,a.VERSION=e,i=null,n=!1,o=[],s=[],"undefined"!=typeof window.google&&delete window.google,"undefined"!=typeof window[a.WINDOW_CALLBACK_NAME]&&delete window[a.WINDOW_CALLBACK_NAME],null!==r&&(a.createLoader=r,r=null),null!==t&&(t.parentElement.removeChild(t),t=null),l&&l()};n?a.load(function(){d()}):d()},a.onLoad=function(e){s.push(e)},a.makeMock=function(){r=a.createLoader,a.createLoader=function(){window.google=a._googleMockApiObject,window[a.WINDOW_CALLBACK_NAME]()}};var l=function(e){var t;for(n=!1,null===i&&(i=window.google),t=0;t":">",'"':""","'":"'","/":"/"},i=e?/[&<>"'\/]/g:/&(?!#?\w+;)|<|>|"|'|\//g;return function(e){return e?e.toString().replace(i,function(e){return t[e]||e}):""}},a=function(){return this||(0,eval)("this")}(),"undefined"!=typeof e&&e.exports?e.exports=l:(n=function(){return l}.call(t,i,t,e),!(void 0!==n&&(e.exports=n)));var d={append:{start:"'+(",end:")+'",startencode:"'+encodeHTML("},split:{start:"';out+=(",end:");out+='",startencode:"';out+=encodeHTML("}},u=/$^/;l.template=function(e,t,i){t=t||l.templateSettings;var n,c,p=t.append?d.append:d.split,h=0,f=t.use||t.define?s(t,e,i||{}):e;f=("var out='"+(t.strip?f.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ").replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""):f).replace(/'|\\/g,"\\$&").replace(t.interpolate||u,function(e,t){return p.start+r(t)+p.end}).replace(t.encode||u,function(e,t){return n=!0,p.startencode+r(t)+p.end}).replace(t.conditional||u,function(e,t,i){return t?i?"';}else if("+r(i)+"){out+='":"';}else{out+='":i?"';if("+r(i)+"){out+='":"';}out+='"}).replace(t.iterate||u,function(e,t,i,n){return t?(h+=1,c=n||"i"+h,t=r(t),"';var arr"+h+"="+t+";if(arr"+h+"){var "+i+","+c+"=-1,l"+h+"=arr"+h+".length-1;while("+c+"this.maxWidth_?(this.div_.style.width=this.maxWidth_,this.fixedWidthSet_=!0):(i=this.getBoxWidths_(),this.div_.style.width=this.div_.offsetWidth-i.left-i.right+"px",this.fixedWidthSet_=!1),this.panBox_(this.disableAutoPan_),!this.enableEventPropagation_){for(this.eventListeners_=[],t=["mousedown","mouseover","mouseout","mouseup","click","dblclick","touchstart","touchend","touchmove"],e=0;er&&(n=f.x+u+l+p-r),this.alignBottom_?f.y<-d+h+c?o=f.y+d-h-c:f.y+d+h>a&&(o=f.y+d+h-a):f.y<-d+h?o=f.y+d-h:f.y+c+d+h>a&&(o=f.y+c+d+h-a),0!==n||0!==o){t.getCenter();t.panBy(n,o)}}},i.prototype.setBoxStyle_=function(){var e,t;if(this.div_){this.div_.className=this.boxClass_,this.div_.style.cssText="",t=this.boxStyle_;for(e in t)t.hasOwnProperty(e)&&(this.div_.style[e]=t[e]);this.div_.style.WebkitTransform="translateZ(0)","undefined"!=typeof this.div_.style.opacity&&""!==this.div_.style.opacity&&(this.div_.style.MsFilter='"progid:DXImageTransform.Microsoft.Alpha(Opacity='+100*this.div_.style.opacity+')"',this.div_.style.filter="alpha(opacity="+100*this.div_.style.opacity+")"),this.div_.style.position="absolute",this.div_.style.visibility="hidden",null!==this.zIndex_&&(this.div_.style.zIndex=this.zIndex_),this.div_.style.overflow||(this.div_.style.overflow="auto")}},i.prototype.getBoxWidths_=function(){var e,t={top:0,bottom:0,left:0,right:0},i=this.div_;return document.defaultView&&document.defaultView.getComputedStyle?(e=i.ownerDocument.defaultView.getComputedStyle(i,""),e&&(t.top=parseInt(e.borderTopWidth,10)||0,t.bottom=parseInt(e.borderBottomWidth,10)||0,t.left=parseInt(e.borderLeftWidth,10)||0,t.right=parseInt(e.borderRightWidth,10)||0)):document.documentElement.currentStyle&&i.currentStyle&&(t.top=parseInt(i.currentStyle.borderTopWidth,10)||0,t.bottom=parseInt(i.currentStyle.borderBottomWidth,10)||0,t.left=parseInt(i.currentStyle.borderLeftWidth,10)||0,t.right=parseInt(i.currentStyle.borderRightWidth,10)||0),t},i.prototype.onRemove=function(){this.div_&&(this.div_.parentNode.removeChild(this.div_),this.div_=null)},i.prototype.draw=function(){this.createInfoBoxDiv_();var e=this.getProjection().fromLatLngToDivPixel(this.position_);this.div_.style.left=e.x+this.pixelOffset_.width+"px",this.alignBottom_?this.div_.style.bottom=-(e.y+this.pixelOffset_.height)+"px":this.div_.style.top=e.y+this.pixelOffset_.height+"px",this.isHidden_?this.div_.style.visibility="hidden":this.div_.style.visibility="visible"},i.prototype.setOptions=function(e){"undefined"!=typeof e.boxClass&&(this.boxClass_=e.boxClass,this.setBoxStyle_()),"undefined"!=typeof e.boxStyle&&(this.boxStyle_=e.boxStyle,this.setBoxStyle_()),"undefined"!=typeof e.content&&this.setContent(e.content),"undefined"!=typeof e.disableAutoPan&&(this.disableAutoPan_=e.disableAutoPan),"undefined"!=typeof e.maxWidth&&(this.maxWidth_=e.maxWidth),"undefined"!=typeof e.pixelOffset&&(this.pixelOffset_=e.pixelOffset),"undefined"!=typeof e.alignBottom&&(this.alignBottom_=e.alignBottom),"undefined"!=typeof e.position&&this.setPosition(e.position),"undefined"!=typeof e.zIndex&&this.setZIndex(e.zIndex),"undefined"!=typeof e.closeBoxMargin&&(this.closeBoxMargin_=e.closeBoxMargin),"undefined"!=typeof e.closeBoxURL&&(this.closeBoxURL_=e.closeBoxURL),"undefined"!=typeof e.infoBoxClearance&&(this.infoBoxClearance_=e.infoBoxClearance),"undefined"!=typeof e.isHidden&&(this.isHidden_=e.isHidden),"undefined"!=typeof e.visible&&(this.isHidden_=!e.visible),"undefined"!=typeof e.enableEventPropagation&&(this.enableEventPropagation_=e.enableEventPropagation),this.div_&&this.draw()},i.prototype.setContent=function(e){this.content_=e,this.div_&&(this.closeListener_&&(google.maps.event.removeListener(this.closeListener_),this.closeListener_=null),this.fixedWidthSet_||(this.div_.style.width=""),"undefined"==typeof e.nodeType?this.div_.innerHTML=this.getCloseBoxImg_()+e:(this.div_.innerHTML=this.getCloseBoxImg_(),this.div_.appendChild(e)),this.fixedWidthSet_||(this.div_.style.width=this.div_.offsetWidth+"px","undefined"==typeof e.nodeType?this.div_.innerHTML=this.getCloseBoxImg_()+e:(this.div_.innerHTML=this.getCloseBoxImg_(),this.div_.appendChild(e))),this.addClickHandler_()),google.maps.event.trigger(this,"content_changed")},i.prototype.setPosition=function(e){this.position_=e,this.div_&&this.draw(),google.maps.event.trigger(this,"position_changed")},i.prototype.setZIndex=function(e){this.zIndex_=e,this.div_&&(this.div_.style.zIndex=e),google.maps.event.trigger(this,"zindex_changed")},i.prototype.setVisible=function(e){this.isHidden_=!e,this.div_&&(this.div_.style.visibility=this.isHidden_?"hidden":"visible")},i.prototype.getContent=function(){return this.content_},i.prototype.getPosition=function(){return this.position_},i.prototype.getZIndex=function(){return this.zIndex_},i.prototype.getVisible=function(){var e;return e="undefined"!=typeof this.getMap()&&null!==this.getMap()&&!this.isHidden_},i.prototype.show=function(){this.isHidden_=!1,this.div_&&(this.div_.style.visibility="visible")},i.prototype.hide=function(){this.isHidden_=!0,this.div_&&(this.div_.style.visibility="hidden")},i.prototype.open=function(e,t){var i=this;t&&(this.position_=t.getPosition(),this.moveListener_=google.maps.event.addListener(t,"position_changed",function(){i.setPosition(this.getPosition())}),this.mapListener_=google.maps.event.addListener(t,"map_changed",function(){i.setMap(this.map)})),this.setMap(e),this.div_&&this.panBox_()},i.prototype.close=function(){var e;if(this.closeListener_&&(google.maps.event.removeListener(this.closeListener_),this.closeListener_=null),this.eventListeners_){for(e=0;e 0) { 660 | url += '&libraries=' + GoogleMapsLoader.LIBRARIES.join(','); 661 | } 662 | 663 | if (GoogleMapsLoader.CLIENT) { 664 | url += '&client=' + GoogleMapsLoader.CLIENT + '&v=' + GoogleMapsLoader.VERSION; 665 | } 666 | 667 | if (GoogleMapsLoader.CHANNEL) { 668 | url += '&channel=' + GoogleMapsLoader.CHANNEL; 669 | } 670 | 671 | if (GoogleMapsLoader.LANGUAGE) { 672 | url += '&language=' + GoogleMapsLoader.LANGUAGE; 673 | } 674 | 675 | if (GoogleMapsLoader.REGION) { 676 | url += '®ion=' + GoogleMapsLoader.REGION; 677 | } 678 | 679 | return url; 680 | }; 681 | 682 | 683 | GoogleMapsLoader.release = function(fn) { 684 | var release = function() { 685 | GoogleMapsLoader.KEY = null; 686 | GoogleMapsLoader.LIBRARIES = []; 687 | GoogleMapsLoader.CLIENT = null; 688 | GoogleMapsLoader.CHANNEL = null; 689 | GoogleMapsLoader.LANGUAGE = null; 690 | GoogleMapsLoader.REGION = null; 691 | GoogleMapsLoader.VERSION = googleVersion; 692 | 693 | google = null; 694 | loading = false; 695 | callbacks = []; 696 | onLoadEvents = []; 697 | 698 | if (typeof window.google !== 'undefined') { 699 | delete window.google; 700 | } 701 | 702 | if (typeof window[GoogleMapsLoader.WINDOW_CALLBACK_NAME] !== 'undefined') { 703 | delete window[GoogleMapsLoader.WINDOW_CALLBACK_NAME]; 704 | } 705 | 706 | if (originalCreateLoaderMethod !== null) { 707 | GoogleMapsLoader.createLoader = originalCreateLoaderMethod; 708 | originalCreateLoaderMethod = null; 709 | } 710 | 711 | if (script !== null) { 712 | script.parentElement.removeChild(script); 713 | script = null; 714 | } 715 | 716 | if (fn) { 717 | fn(); 718 | } 719 | }; 720 | 721 | if (loading) { 722 | GoogleMapsLoader.load(function() { 723 | release(); 724 | }); 725 | } else { 726 | release(); 727 | } 728 | }; 729 | 730 | 731 | GoogleMapsLoader.onLoad = function(fn) { 732 | onLoadEvents.push(fn); 733 | }; 734 | 735 | 736 | GoogleMapsLoader.makeMock = function() { 737 | originalCreateLoaderMethod = GoogleMapsLoader.createLoader; 738 | 739 | GoogleMapsLoader.createLoader = function() { 740 | window.google = GoogleMapsLoader._googleMockApiObject; 741 | window[GoogleMapsLoader.WINDOW_CALLBACK_NAME](); 742 | }; 743 | }; 744 | 745 | 746 | var ready = function(fn) { 747 | var i; 748 | 749 | loading = false; 750 | 751 | if (google === null) { 752 | google = window.google; 753 | } 754 | 755 | for (i = 0; i < onLoadEvents.length; i++) { 756 | onLoadEvents[i](google); 757 | } 758 | 759 | if (fn) { 760 | fn(google); 761 | } 762 | 763 | for (i = 0; i < callbacks.length; i++) { 764 | callbacks[i](google); 765 | } 766 | 767 | callbacks = []; 768 | }; 769 | 770 | 771 | return GoogleMapsLoader; 772 | 773 | }); 774 | 775 | 776 | /***/ }, 777 | /* 3 */ 778 | /***/ function(module, exports, __webpack_require__) { 779 | 780 | /* WEBPACK VAR INJECTION */(function(console) {/* doT + auto-compilation of doT templates 781 | * 782 | * 2012, Laura Doktorova, https://github.com/olado/doT 783 | * Licensed under the MIT license 784 | * 785 | * Compiles .def, .dot, .jst files found under the specified path. 786 | * It ignores sub-directories. 787 | * Template files can have multiple extensions at the same time. 788 | * Files with .def extension can be included in other files via {{#def.name}} 789 | * Files with .dot extension are compiled into functions with the same name and 790 | * can be accessed as renderer.filename 791 | * Files with .jst extension are compiled into .js files. Produced .js file can be 792 | * loaded as a commonJS, AMD module, or just installed into a global variable 793 | * (default is set to window.render). 794 | * All inline defines defined in the .jst file are 795 | * compiled into separate functions and are available via _render.filename.definename 796 | * 797 | * Basic usage: 798 | * var dots = require("dot").process({path: "./views"}); 799 | * dots.mytemplate({foo:"hello world"}); 800 | * 801 | * The above snippet will: 802 | * 1. Compile all templates in views folder (.dot, .def, .jst) 803 | * 2. Place .js files compiled from .jst templates into the same folder. 804 | * These files can be used with require, i.e. require("./views/mytemplate"). 805 | * 3. Return an object with functions compiled from .dot templates as its properties. 806 | * 4. Render mytemplate template. 807 | */ 808 | 809 | var fs = __webpack_require__(1), 810 | doT = module.exports = __webpack_require__(4); 811 | 812 | doT.process = function(options) { 813 | //path, destination, global, rendermodule, templateSettings 814 | return new InstallDots(options).compileAll(); 815 | }; 816 | 817 | function InstallDots(o) { 818 | this.__path = o.path || "./"; 819 | if (this.__path[this.__path.length-1] !== '/') this.__path += '/'; 820 | this.__destination = o.destination || this.__path; 821 | if (this.__destination[this.__destination.length-1] !== '/') this.__destination += '/'; 822 | this.__global = o.global || "window.render"; 823 | this.__rendermodule = o.rendermodule || {}; 824 | this.__settings = o.templateSettings ? copy(o.templateSettings, copy(doT.templateSettings)) : undefined; 825 | this.__includes = {}; 826 | } 827 | 828 | InstallDots.prototype.compileToFile = function(path, template, def) { 829 | def = def || {}; 830 | var modulename = path.substring(path.lastIndexOf("/")+1, path.lastIndexOf(".")) 831 | , defs = copy(this.__includes, copy(def)) 832 | , settings = this.__settings || doT.templateSettings 833 | , compileoptions = copy(settings) 834 | , defaultcompiled = doT.template(template, settings, defs) 835 | , exports = [] 836 | , compiled = "" 837 | , fn; 838 | 839 | for (var property in defs) { 840 | if (defs[property] !== def[property] && defs[property] !== this.__includes[property]) { 841 | fn = undefined; 842 | if (typeof defs[property] === 'string') { 843 | fn = doT.template(defs[property], settings, defs); 844 | } else if (typeof defs[property] === 'function') { 845 | fn = defs[property]; 846 | } else if (defs[property].arg) { 847 | compileoptions.varname = defs[property].arg; 848 | fn = doT.template(defs[property].text, compileoptions, defs); 849 | } 850 | if (fn) { 851 | compiled += fn.toString().replace('anonymous', property); 852 | exports.push(property); 853 | } 854 | } 855 | } 856 | compiled += defaultcompiled.toString().replace('anonymous', modulename); 857 | fs.writeFileSync(path, "(function(){" + compiled 858 | + "var itself=" + modulename + ", _encodeHTML=(" + doT.encodeHTMLSource.toString() + "(" + (settings.doNotSkipEncoded || '') + "));" 859 | + addexports(exports) 860 | + "if(typeof module!=='undefined' && module.exports) module.exports=itself;else if(typeof define==='function')define(function(){return itself;});else {" 861 | + this.__global + "=" + this.__global + "||{};" + this.__global + "['" + modulename + "']=itself;}}());"); 862 | }; 863 | 864 | function addexports(exports) { 865 | var ret = ''; 866 | for (var i=0; i< exports.length; i++) { 867 | ret += "itself." + exports[i]+ "=" + exports[i]+";"; 868 | } 869 | return ret; 870 | } 871 | 872 | function copy(o, to) { 873 | to = to || {}; 874 | for (var property in o) { 875 | to[property] = o[property]; 876 | } 877 | return to; 878 | } 879 | 880 | function readdata(path) { 881 | var data = fs.readFileSync(path); 882 | if (data) return data.toString(); 883 | console.log("problems with " + path); 884 | } 885 | 886 | InstallDots.prototype.compilePath = function(path) { 887 | var data = readdata(path); 888 | if (data) { 889 | return doT.template(data, 890 | this.__settings || doT.templateSettings, 891 | copy(this.__includes)); 892 | } 893 | }; 894 | 895 | InstallDots.prototype.compileAll = function() { 896 | if (doT.log) console.log("Compiling all doT templates..."); 897 | 898 | var defFolder = this.__path, 899 | sources = fs.readdirSync(defFolder), 900 | k, l, name; 901 | 902 | for( k = 0, l = sources.length; k < l; k++) { 903 | name = sources[k]; 904 | if (/\.def(\.dot|\.jst)?$/.test(name)) { 905 | if (doT.log) console.log("Loaded def " + name); 906 | this.__includes[name.substring(0, name.indexOf('.'))] = readdata(defFolder + name); 907 | } 908 | } 909 | 910 | for( k = 0, l = sources.length; k < l; k++) { 911 | name = sources[k]; 912 | if (/\.dot(\.def|\.jst)?$/.test(name)) { 913 | if (doT.log) console.log("Compiling " + name + " to function"); 914 | this.__rendermodule[name.substring(0, name.indexOf('.'))] = this.compilePath(defFolder + name); 915 | } 916 | if (/\.jst(\.dot|\.def)?$/.test(name)) { 917 | if (doT.log) console.log("Compiling " + name + " to file"); 918 | this.compileToFile(this.__destination + name.substring(0, name.indexOf('.')) + '.js', 919 | readdata(defFolder + name)); 920 | } 921 | } 922 | return this.__rendermodule; 923 | }; 924 | 925 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1))) 926 | 927 | /***/ }, 928 | /* 4 */ 929 | /***/ function(module, exports, __webpack_require__) { 930 | 931 | var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(console) {// doT.js 932 | // 2011-2014, Laura Doktorova, https://github.com/olado/doT 933 | // Licensed under the MIT license. 934 | 935 | (function() { 936 | "use strict"; 937 | 938 | var doT = { 939 | version: "1.1.1", 940 | templateSettings: { 941 | evaluate: /\{\{([\s\S]+?(\}?)+)\}\}/g, 942 | interpolate: /\{\{=([\s\S]+?)\}\}/g, 943 | encode: /\{\{!([\s\S]+?)\}\}/g, 944 | use: /\{\{#([\s\S]+?)\}\}/g, 945 | useParams: /(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g, 946 | define: /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g, 947 | defineParams:/^\s*([\w$]+):([\s\S]+)/, 948 | conditional: /\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g, 949 | iterate: /\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g, 950 | varname: "it", 951 | strip: true, 952 | append: true, 953 | selfcontained: false, 954 | doNotSkipEncoded: false 955 | }, 956 | template: undefined, //fn, compile template 957 | compile: undefined, //fn, for express 958 | log: true 959 | }, _globals; 960 | 961 | doT.encodeHTMLSource = function(doNotSkipEncoded) { 962 | var encodeHTMLRules = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'", "/": "/" }, 963 | matchHTML = doNotSkipEncoded ? /[&<>"'\/]/g : /&(?!#?\w+;)|<|>|"|'|\//g; 964 | return function(code) { 965 | return code ? code.toString().replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : ""; 966 | }; 967 | }; 968 | 969 | _globals = (function(){ return this || (0,eval)("this"); }()); 970 | 971 | /* istanbul ignore else */ 972 | if (typeof module !== "undefined" && module.exports) { 973 | module.exports = doT; 974 | } else if (true) { 975 | !(__WEBPACK_AMD_DEFINE_RESULT__ = function(){return doT;}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 976 | } else { 977 | _globals.doT = doT; 978 | } 979 | 980 | var startend = { 981 | append: { start: "'+(", end: ")+'", startencode: "'+encodeHTML(" }, 982 | split: { start: "';out+=(", end: ");out+='", startencode: "';out+=encodeHTML(" } 983 | }, skip = /$^/; 984 | 985 | function resolveDefs(c, block, def) { 986 | return ((typeof block === "string") ? block : block.toString()) 987 | .replace(c.define || skip, function(m, code, assign, value) { 988 | if (code.indexOf("def.") === 0) { 989 | code = code.substring(4); 990 | } 991 | if (!(code in def)) { 992 | if (assign === ":") { 993 | if (c.defineParams) value.replace(c.defineParams, function(m, param, v) { 994 | def[code] = {arg: param, text: v}; 995 | }); 996 | if (!(code in def)) def[code]= value; 997 | } else { 998 | new Function("def", "def['"+code+"']=" + value)(def); 999 | } 1000 | } 1001 | return ""; 1002 | }) 1003 | .replace(c.use || skip, function(m, code) { 1004 | if (c.useParams) code = code.replace(c.useParams, function(m, s, d, param) { 1005 | if (def[d] && def[d].arg && param) { 1006 | var rw = (d+":"+param).replace(/'|\\/g, "_"); 1007 | def.__exp = def.__exp || {}; 1008 | def.__exp[rw] = def[d].text.replace(new RegExp("(^|[^\\w$])" + def[d].arg + "([^\\w$])", "g"), "$1" + param + "$2"); 1009 | return s + "def.__exp['"+rw+"']"; 1010 | } 1011 | }); 1012 | var v = new Function("def", "return " + code)(def); 1013 | return v ? resolveDefs(c, v, def) : v; 1014 | }); 1015 | } 1016 | 1017 | function unescape(code) { 1018 | return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, " "); 1019 | } 1020 | 1021 | doT.template = function(tmpl, c, def) { 1022 | c = c || doT.templateSettings; 1023 | var cse = c.append ? startend.append : startend.split, needhtmlencode, sid = 0, indv, 1024 | str = (c.use || c.define) ? resolveDefs(c, tmpl, def || {}) : tmpl; 1025 | 1026 | str = ("var out='" + (c.strip ? str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ") 1027 | .replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""): str) 1028 | .replace(/'|\\/g, "\\$&") 1029 | .replace(c.interpolate || skip, function(m, code) { 1030 | return cse.start + unescape(code) + cse.end; 1031 | }) 1032 | .replace(c.encode || skip, function(m, code) { 1033 | needhtmlencode = true; 1034 | return cse.startencode + unescape(code) + cse.end; 1035 | }) 1036 | .replace(c.conditional || skip, function(m, elsecase, code) { 1037 | return elsecase ? 1038 | (code ? "';}else if(" + unescape(code) + "){out+='" : "';}else{out+='") : 1039 | (code ? "';if(" + unescape(code) + "){out+='" : "';}out+='"); 1040 | }) 1041 | .replace(c.iterate || skip, function(m, iterate, vname, iname) { 1042 | if (!iterate) return "';} } out+='"; 1043 | sid+=1; indv=iname || "i"+sid; iterate=unescape(iterate); 1044 | return "';var arr"+sid+"="+iterate+";if(arr"+sid+"){var "+vname+","+indv+"=-1,l"+sid+"=arr"+sid+".length-1;while("+indv+"OverlayView class. 1087 | *

1088 | * An InfoBox behaves like a google.maps.InfoWindow, but it supports several 1089 | * additional properties for advanced styling. An InfoBox can also be used as a map label. 1090 | *

1091 | * An InfoBox also fires the same events as a google.maps.InfoWindow. 1092 | */ 1093 | 1094 | /*! 1095 | * 1096 | * Licensed under the Apache License, Version 2.0 (the "License"); 1097 | * you may not use this file except in compliance with the License. 1098 | * You may obtain a copy of the License at 1099 | * 1100 | * http://www.apache.org/licenses/LICENSE-2.0 1101 | * 1102 | * Unless required by applicable law or agreed to in writing, software 1103 | * distributed under the License is distributed on an "AS IS" BASIS, 1104 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1105 | * See the License for the specific language governing permissions and 1106 | * limitations under the License. 1107 | */ 1108 | 1109 | /*jslint browser:true */ 1110 | /*global google */ 1111 | 1112 | /** 1113 | * @name InfoBoxOptions 1114 | * @class This class represents the optional parameter passed to the {@link InfoBox} constructor. 1115 | * @property {string|Node} content The content of the InfoBox (plain text or an HTML DOM node). 1116 | * @property {boolean} [disableAutoPan=false] Disable auto-pan on open. 1117 | * @property {number} maxWidth The maximum width (in pixels) of the InfoBox. Set to 0 if no maximum. 1118 | * @property {Size} pixelOffset The offset (in pixels) from the top left corner of the InfoBox 1119 | * (or the bottom left corner if the alignBottom property is true) 1120 | * to the map pixel corresponding to position. 1121 | * @property {LatLng} position The geographic location at which to display the InfoBox. 1122 | * @property {number} zIndex The CSS z-index style value for the InfoBox. 1123 | * Note: This value overrides a zIndex setting specified in the boxStyle property. 1124 | * @property {string} [boxClass="infoBox"] The name of the CSS class defining the styles for the InfoBox container. 1125 | * @property {Object} [boxStyle] An object literal whose properties define specific CSS 1126 | * style values to be applied to the InfoBox. Style values defined here override those that may 1127 | * be defined in the boxClass style sheet. If this property is changed after the 1128 | * InfoBox has been created, all previously set styles (except those defined in the style sheet) 1129 | * are removed from the InfoBox before the new style values are applied. 1130 | * @property {string} closeBoxMargin The CSS margin style value for the close box. 1131 | * The default is "2px" (a 2-pixel margin on all sides). 1132 | * @property {string} closeBoxURL The URL of the image representing the close box. 1133 | * Note: The default is the URL for Google's standard close box. 1134 | * Set this property to "" if no close box is required. 1135 | * @property {Size} infoBoxClearance Minimum offset (in pixels) from the InfoBox to the 1136 | * map edge after an auto-pan. 1137 | * @property {boolean} [isHidden=false] Hide the InfoBox on open. 1138 | * [Deprecated in favor of the visible property.] 1139 | * @property {boolean} [visible=true] Show the InfoBox on open. 1140 | * @property {boolean} alignBottom Align the bottom left corner of the InfoBox to the position 1141 | * location (default is false which means that the top left corner of the InfoBox is aligned). 1142 | * @property {string} pane The pane where the InfoBox is to appear (default is "floatPane"). 1143 | * Set the pane to "mapPane" if the InfoBox is being used as a map label. 1144 | * Valid pane names are the property names for the google.maps.MapPanes object. 1145 | * @property {boolean} enableEventPropagation Propagate mousedown, mousemove, mouseover, mouseout, 1146 | * mouseup, click, dblclick, touchstart, touchend, touchmove, and contextmenu events in the InfoBox 1147 | * (default is false to mimic the behavior of a google.maps.InfoWindow). Set 1148 | * this property to true if the InfoBox is being used as a map label. 1149 | */ 1150 | 1151 | /** 1152 | * Creates an InfoBox with the options specified in {@link InfoBoxOptions}. 1153 | * Call InfoBox.open to add the box to the map. 1154 | * @constructor 1155 | * @param {InfoBoxOptions} [opt_opts] 1156 | */ 1157 | function InfoBox(opt_opts) { 1158 | 1159 | opt_opts = opt_opts || {}; 1160 | 1161 | google.maps.OverlayView.apply(this, arguments); 1162 | 1163 | // Standard options (in common with google.maps.InfoWindow): 1164 | // 1165 | this.content_ = opt_opts.content || ""; 1166 | this.disableAutoPan_ = opt_opts.disableAutoPan || false; 1167 | this.maxWidth_ = opt_opts.maxWidth || 0; 1168 | this.pixelOffset_ = opt_opts.pixelOffset || new google.maps.Size(0, 0); 1169 | this.position_ = opt_opts.position || new google.maps.LatLng(0, 0); 1170 | this.zIndex_ = opt_opts.zIndex || null; 1171 | 1172 | // Additional options (unique to InfoBox): 1173 | // 1174 | this.boxClass_ = opt_opts.boxClass || "infoBox"; 1175 | this.boxStyle_ = opt_opts.boxStyle || {}; 1176 | this.closeBoxMargin_ = opt_opts.closeBoxMargin || "2px"; 1177 | this.closeBoxURL_ = opt_opts.closeBoxURL || "http://www.google.com/intl/en_us/mapfiles/close.gif"; 1178 | if (opt_opts.closeBoxURL === "") { 1179 | this.closeBoxURL_ = ""; 1180 | } 1181 | this.infoBoxClearance_ = opt_opts.infoBoxClearance || new google.maps.Size(1, 1); 1182 | 1183 | if (typeof opt_opts.visible === "undefined") { 1184 | if (typeof opt_opts.isHidden === "undefined") { 1185 | opt_opts.visible = true; 1186 | } else { 1187 | opt_opts.visible = !opt_opts.isHidden; 1188 | } 1189 | } 1190 | this.isHidden_ = !opt_opts.visible; 1191 | 1192 | this.alignBottom_ = opt_opts.alignBottom || false; 1193 | this.pane_ = opt_opts.pane || "floatPane"; 1194 | this.enableEventPropagation_ = opt_opts.enableEventPropagation || false; 1195 | 1196 | this.div_ = null; 1197 | this.closeListener_ = null; 1198 | this.moveListener_ = null; 1199 | this.mapListener_ = null; 1200 | this.contextListener_ = null; 1201 | this.eventListeners_ = null; 1202 | this.fixedWidthSet_ = null; 1203 | } 1204 | 1205 | /* InfoBox extends OverlayView in the Google Maps API v3. 1206 | */ 1207 | InfoBox.prototype = new google.maps.OverlayView(); 1208 | 1209 | /** 1210 | * Creates the DIV representing the InfoBox. 1211 | * @private 1212 | */ 1213 | InfoBox.prototype.createInfoBoxDiv_ = function () { 1214 | 1215 | var i; 1216 | var events; 1217 | var bw; 1218 | var me = this; 1219 | 1220 | // This handler prevents an event in the InfoBox from being passed on to the map. 1221 | // 1222 | var cancelHandler = function (e) { 1223 | e.cancelBubble = true; 1224 | if (e.stopPropagation) { 1225 | e.stopPropagation(); 1226 | } 1227 | }; 1228 | 1229 | // This handler ignores the current event in the InfoBox and conditionally prevents 1230 | // the event from being passed on to the map. It is used for the contextmenu event. 1231 | // 1232 | var ignoreHandler = function (e) { 1233 | 1234 | e.returnValue = false; 1235 | 1236 | if (e.preventDefault) { 1237 | 1238 | e.preventDefault(); 1239 | } 1240 | 1241 | if (!me.enableEventPropagation_) { 1242 | 1243 | cancelHandler(e); 1244 | } 1245 | }; 1246 | 1247 | if (!this.div_) { 1248 | 1249 | this.div_ = document.createElement("div"); 1250 | 1251 | this.setBoxStyle_(); 1252 | 1253 | if (typeof this.content_.nodeType === "undefined") { 1254 | this.div_.innerHTML = this.getCloseBoxImg_() + this.content_; 1255 | } else { 1256 | this.div_.innerHTML = this.getCloseBoxImg_(); 1257 | this.div_.appendChild(this.content_); 1258 | } 1259 | 1260 | // Add the InfoBox DIV to the DOM 1261 | this.getPanes()[this.pane_].appendChild(this.div_); 1262 | 1263 | this.addClickHandler_(); 1264 | 1265 | if (this.div_.style.width) { 1266 | 1267 | this.fixedWidthSet_ = true; 1268 | 1269 | } else { 1270 | 1271 | if (this.maxWidth_ !== 0 && this.div_.offsetWidth > this.maxWidth_) { 1272 | 1273 | this.div_.style.width = this.maxWidth_; 1274 | this.fixedWidthSet_ = true; 1275 | 1276 | } else { // The following code is needed to overcome problems with MSIE 1277 | 1278 | bw = this.getBoxWidths_(); 1279 | 1280 | this.div_.style.width = (this.div_.offsetWidth - bw.left - bw.right) + "px"; 1281 | this.fixedWidthSet_ = false; 1282 | } 1283 | } 1284 | 1285 | this.panBox_(this.disableAutoPan_); 1286 | 1287 | if (!this.enableEventPropagation_) { 1288 | 1289 | this.eventListeners_ = []; 1290 | 1291 | // Cancel event propagation. 1292 | // 1293 | // Note: mousemove not included (to resolve Issue 152) 1294 | events = ["mousedown", "mouseover", "mouseout", "mouseup", 1295 | "click", "dblclick", "touchstart", "touchend", "touchmove"]; 1296 | 1297 | for (i = 0; i < events.length; i++) { 1298 | 1299 | this.eventListeners_.push(google.maps.event.addDomListener(this.div_, events[i], cancelHandler)); 1300 | } 1301 | 1302 | // Workaround for Google bug that causes the cursor to change to a pointer 1303 | // when the mouse moves over a marker underneath InfoBox. 1304 | this.eventListeners_.push(google.maps.event.addDomListener(this.div_, "mouseover", function (e) { 1305 | this.style.cursor = "default"; 1306 | })); 1307 | } 1308 | 1309 | this.contextListener_ = google.maps.event.addDomListener(this.div_, "contextmenu", ignoreHandler); 1310 | 1311 | /** 1312 | * This event is fired when the DIV containing the InfoBox's content is attached to the DOM. 1313 | * @name InfoBox#domready 1314 | * @event 1315 | */ 1316 | google.maps.event.trigger(this, "domready"); 1317 | } 1318 | }; 1319 | 1320 | /** 1321 | * Returns the HTML tag for the close box. 1322 | * @private 1323 | */ 1324 | InfoBox.prototype.getCloseBoxImg_ = function () { 1325 | 1326 | var img = ""; 1327 | 1328 | if (this.closeBoxURL_ !== "") { 1329 | 1330 | img = " mapWidth) { 1429 | xOffset = pixPosition.x + iwWidth + iwOffsetX + padX - mapWidth; 1430 | } 1431 | if (this.alignBottom_) { 1432 | if (pixPosition.y < (-iwOffsetY + padY + iwHeight)) { 1433 | yOffset = pixPosition.y + iwOffsetY - padY - iwHeight; 1434 | } else if ((pixPosition.y + iwOffsetY + padY) > mapHeight) { 1435 | yOffset = pixPosition.y + iwOffsetY + padY - mapHeight; 1436 | } 1437 | } else { 1438 | if (pixPosition.y < (-iwOffsetY + padY)) { 1439 | yOffset = pixPosition.y + iwOffsetY - padY; 1440 | } else if ((pixPosition.y + iwHeight + iwOffsetY + padY) > mapHeight) { 1441 | yOffset = pixPosition.y + iwHeight + iwOffsetY + padY - mapHeight; 1442 | } 1443 | } 1444 | 1445 | if (!(xOffset === 0 && yOffset === 0)) { 1446 | 1447 | // Move the map to the shifted center. 1448 | // 1449 | var c = map.getCenter(); 1450 | map.panBy(xOffset, yOffset); 1451 | } 1452 | } 1453 | } 1454 | }; 1455 | 1456 | /** 1457 | * Sets the style of the InfoBox by setting the style sheet and applying 1458 | * other specific styles requested. 1459 | * @private 1460 | */ 1461 | InfoBox.prototype.setBoxStyle_ = function () { 1462 | 1463 | var i, boxStyle; 1464 | 1465 | if (this.div_) { 1466 | 1467 | // Apply style values from the style sheet defined in the boxClass parameter: 1468 | this.div_.className = this.boxClass_; 1469 | 1470 | // Clear existing inline style values: 1471 | this.div_.style.cssText = ""; 1472 | 1473 | // Apply style values defined in the boxStyle parameter: 1474 | boxStyle = this.boxStyle_; 1475 | for (i in boxStyle) { 1476 | 1477 | if (boxStyle.hasOwnProperty(i)) { 1478 | 1479 | this.div_.style[i] = boxStyle[i]; 1480 | } 1481 | } 1482 | 1483 | // Fix for iOS disappearing InfoBox problem. 1484 | // See http://stackoverflow.com/questions/9229535/google-maps-markers-disappear-at-certain-zoom-level-only-on-iphone-ipad 1485 | this.div_.style.WebkitTransform = "translateZ(0)"; 1486 | 1487 | // Fix up opacity style for benefit of MSIE: 1488 | // 1489 | if (typeof this.div_.style.opacity !== "undefined" && this.div_.style.opacity !== "") { 1490 | // See http://www.quirksmode.org/css/opacity.html 1491 | this.div_.style.MsFilter = "\"progid:DXImageTransform.Microsoft.Alpha(Opacity=" + (this.div_.style.opacity * 100) + ")\""; 1492 | this.div_.style.filter = "alpha(opacity=" + (this.div_.style.opacity * 100) + ")"; 1493 | } 1494 | 1495 | // Apply required styles: 1496 | // 1497 | this.div_.style.position = "absolute"; 1498 | this.div_.style.visibility = 'hidden'; 1499 | if (this.zIndex_ !== null) { 1500 | 1501 | this.div_.style.zIndex = this.zIndex_; 1502 | } 1503 | if (!this.div_.style.overflow) { 1504 | this.div_.style.overflow = "auto"; 1505 | } 1506 | } 1507 | }; 1508 | 1509 | /** 1510 | * Get the widths of the borders of the InfoBox. 1511 | * @private 1512 | * @return {Object} widths object (top, bottom left, right) 1513 | */ 1514 | InfoBox.prototype.getBoxWidths_ = function () { 1515 | 1516 | var computedStyle; 1517 | var bw = {top: 0, bottom: 0, left: 0, right: 0}; 1518 | var box = this.div_; 1519 | 1520 | if (document.defaultView && document.defaultView.getComputedStyle) { 1521 | 1522 | computedStyle = box.ownerDocument.defaultView.getComputedStyle(box, ""); 1523 | 1524 | if (computedStyle) { 1525 | 1526 | // The computed styles are always in pixel units (good!) 1527 | bw.top = parseInt(computedStyle.borderTopWidth, 10) || 0; 1528 | bw.bottom = parseInt(computedStyle.borderBottomWidth, 10) || 0; 1529 | bw.left = parseInt(computedStyle.borderLeftWidth, 10) || 0; 1530 | bw.right = parseInt(computedStyle.borderRightWidth, 10) || 0; 1531 | } 1532 | 1533 | } else if (document.documentElement.currentStyle) { // MSIE 1534 | 1535 | if (box.currentStyle) { 1536 | 1537 | // The current styles may not be in pixel units, but assume they are (bad!) 1538 | bw.top = parseInt(box.currentStyle.borderTopWidth, 10) || 0; 1539 | bw.bottom = parseInt(box.currentStyle.borderBottomWidth, 10) || 0; 1540 | bw.left = parseInt(box.currentStyle.borderLeftWidth, 10) || 0; 1541 | bw.right = parseInt(box.currentStyle.borderRightWidth, 10) || 0; 1542 | } 1543 | } 1544 | 1545 | return bw; 1546 | }; 1547 | 1548 | /** 1549 | * Invoked when close is called. Do not call it directly. 1550 | */ 1551 | InfoBox.prototype.onRemove = function () { 1552 | 1553 | if (this.div_) { 1554 | 1555 | this.div_.parentNode.removeChild(this.div_); 1556 | this.div_ = null; 1557 | } 1558 | }; 1559 | 1560 | /** 1561 | * Draws the InfoBox based on the current map projection and zoom level. 1562 | */ 1563 | InfoBox.prototype.draw = function () { 1564 | 1565 | this.createInfoBoxDiv_(); 1566 | 1567 | var pixPosition = this.getProjection().fromLatLngToDivPixel(this.position_); 1568 | 1569 | this.div_.style.left = (pixPosition.x + this.pixelOffset_.width) + "px"; 1570 | 1571 | if (this.alignBottom_) { 1572 | this.div_.style.bottom = -(pixPosition.y + this.pixelOffset_.height) + "px"; 1573 | } else { 1574 | this.div_.style.top = (pixPosition.y + this.pixelOffset_.height) + "px"; 1575 | } 1576 | 1577 | if (this.isHidden_) { 1578 | 1579 | this.div_.style.visibility = "hidden"; 1580 | 1581 | } else { 1582 | 1583 | this.div_.style.visibility = "visible"; 1584 | } 1585 | }; 1586 | 1587 | /** 1588 | * Sets the options for the InfoBox. Note that changes to the maxWidth, 1589 | * closeBoxMargin, closeBoxURL, and enableEventPropagation 1590 | * properties have no affect until the current InfoBox is closed and a new one 1591 | * is opened. 1592 | * @param {InfoBoxOptions} opt_opts 1593 | */ 1594 | InfoBox.prototype.setOptions = function (opt_opts) { 1595 | if (typeof opt_opts.boxClass !== "undefined") { // Must be first 1596 | 1597 | this.boxClass_ = opt_opts.boxClass; 1598 | this.setBoxStyle_(); 1599 | } 1600 | if (typeof opt_opts.boxStyle !== "undefined") { // Must be second 1601 | 1602 | this.boxStyle_ = opt_opts.boxStyle; 1603 | this.setBoxStyle_(); 1604 | } 1605 | if (typeof opt_opts.content !== "undefined") { 1606 | 1607 | this.setContent(opt_opts.content); 1608 | } 1609 | if (typeof opt_opts.disableAutoPan !== "undefined") { 1610 | 1611 | this.disableAutoPan_ = opt_opts.disableAutoPan; 1612 | } 1613 | if (typeof opt_opts.maxWidth !== "undefined") { 1614 | 1615 | this.maxWidth_ = opt_opts.maxWidth; 1616 | } 1617 | if (typeof opt_opts.pixelOffset !== "undefined") { 1618 | 1619 | this.pixelOffset_ = opt_opts.pixelOffset; 1620 | } 1621 | if (typeof opt_opts.alignBottom !== "undefined") { 1622 | 1623 | this.alignBottom_ = opt_opts.alignBottom; 1624 | } 1625 | if (typeof opt_opts.position !== "undefined") { 1626 | 1627 | this.setPosition(opt_opts.position); 1628 | } 1629 | if (typeof opt_opts.zIndex !== "undefined") { 1630 | 1631 | this.setZIndex(opt_opts.zIndex); 1632 | } 1633 | if (typeof opt_opts.closeBoxMargin !== "undefined") { 1634 | 1635 | this.closeBoxMargin_ = opt_opts.closeBoxMargin; 1636 | } 1637 | if (typeof opt_opts.closeBoxURL !== "undefined") { 1638 | 1639 | this.closeBoxURL_ = opt_opts.closeBoxURL; 1640 | } 1641 | if (typeof opt_opts.infoBoxClearance !== "undefined") { 1642 | 1643 | this.infoBoxClearance_ = opt_opts.infoBoxClearance; 1644 | } 1645 | if (typeof opt_opts.isHidden !== "undefined") { 1646 | 1647 | this.isHidden_ = opt_opts.isHidden; 1648 | } 1649 | if (typeof opt_opts.visible !== "undefined") { 1650 | 1651 | this.isHidden_ = !opt_opts.visible; 1652 | } 1653 | if (typeof opt_opts.enableEventPropagation !== "undefined") { 1654 | 1655 | this.enableEventPropagation_ = opt_opts.enableEventPropagation; 1656 | } 1657 | 1658 | if (this.div_) { 1659 | 1660 | this.draw(); 1661 | } 1662 | }; 1663 | 1664 | /** 1665 | * Sets the content of the InfoBox. 1666 | * The content can be plain text or an HTML DOM node. 1667 | * @param {string|Node} content 1668 | */ 1669 | InfoBox.prototype.setContent = function (content) { 1670 | this.content_ = content; 1671 | 1672 | if (this.div_) { 1673 | 1674 | if (this.closeListener_) { 1675 | 1676 | google.maps.event.removeListener(this.closeListener_); 1677 | this.closeListener_ = null; 1678 | } 1679 | 1680 | // Odd code required to make things work with MSIE. 1681 | // 1682 | if (!this.fixedWidthSet_) { 1683 | 1684 | this.div_.style.width = ""; 1685 | } 1686 | 1687 | if (typeof content.nodeType === "undefined") { 1688 | this.div_.innerHTML = this.getCloseBoxImg_() + content; 1689 | } else { 1690 | this.div_.innerHTML = this.getCloseBoxImg_(); 1691 | this.div_.appendChild(content); 1692 | } 1693 | 1694 | // Perverse code required to make things work with MSIE. 1695 | // (Ensures the close box does, in fact, float to the right.) 1696 | // 1697 | if (!this.fixedWidthSet_) { 1698 | this.div_.style.width = this.div_.offsetWidth + "px"; 1699 | if (typeof content.nodeType === "undefined") { 1700 | this.div_.innerHTML = this.getCloseBoxImg_() + content; 1701 | } else { 1702 | this.div_.innerHTML = this.getCloseBoxImg_(); 1703 | this.div_.appendChild(content); 1704 | } 1705 | } 1706 | 1707 | this.addClickHandler_(); 1708 | } 1709 | 1710 | /** 1711 | * This event is fired when the content of the InfoBox changes. 1712 | * @name InfoBox#content_changed 1713 | * @event 1714 | */ 1715 | google.maps.event.trigger(this, "content_changed"); 1716 | }; 1717 | 1718 | /** 1719 | * Sets the geographic location of the InfoBox. 1720 | * @param {LatLng} latlng 1721 | */ 1722 | InfoBox.prototype.setPosition = function (latlng) { 1723 | 1724 | this.position_ = latlng; 1725 | 1726 | if (this.div_) { 1727 | 1728 | this.draw(); 1729 | } 1730 | 1731 | /** 1732 | * This event is fired when the position of the InfoBox changes. 1733 | * @name InfoBox#position_changed 1734 | * @event 1735 | */ 1736 | google.maps.event.trigger(this, "position_changed"); 1737 | }; 1738 | 1739 | /** 1740 | * Sets the zIndex style for the InfoBox. 1741 | * @param {number} index 1742 | */ 1743 | InfoBox.prototype.setZIndex = function (index) { 1744 | 1745 | this.zIndex_ = index; 1746 | 1747 | if (this.div_) { 1748 | 1749 | this.div_.style.zIndex = index; 1750 | } 1751 | 1752 | /** 1753 | * This event is fired when the zIndex of the InfoBox changes. 1754 | * @name InfoBox#zindex_changed 1755 | * @event 1756 | */ 1757 | google.maps.event.trigger(this, "zindex_changed"); 1758 | }; 1759 | 1760 | /** 1761 | * Sets the visibility of the InfoBox. 1762 | * @param {boolean} isVisible 1763 | */ 1764 | InfoBox.prototype.setVisible = function (isVisible) { 1765 | 1766 | this.isHidden_ = !isVisible; 1767 | if (this.div_) { 1768 | this.div_.style.visibility = (this.isHidden_ ? "hidden" : "visible"); 1769 | } 1770 | }; 1771 | 1772 | /** 1773 | * Returns the content of the InfoBox. 1774 | * @returns {string} 1775 | */ 1776 | InfoBox.prototype.getContent = function () { 1777 | 1778 | return this.content_; 1779 | }; 1780 | 1781 | /** 1782 | * Returns the geographic location of the InfoBox. 1783 | * @returns {LatLng} 1784 | */ 1785 | InfoBox.prototype.getPosition = function () { 1786 | 1787 | return this.position_; 1788 | }; 1789 | 1790 | /** 1791 | * Returns the zIndex for the InfoBox. 1792 | * @returns {number} 1793 | */ 1794 | InfoBox.prototype.getZIndex = function () { 1795 | 1796 | return this.zIndex_; 1797 | }; 1798 | 1799 | /** 1800 | * Returns a flag indicating whether the InfoBox is visible. 1801 | * @returns {boolean} 1802 | */ 1803 | InfoBox.prototype.getVisible = function () { 1804 | 1805 | var isVisible; 1806 | 1807 | if ((typeof this.getMap() === "undefined") || (this.getMap() === null)) { 1808 | isVisible = false; 1809 | } else { 1810 | isVisible = !this.isHidden_; 1811 | } 1812 | return isVisible; 1813 | }; 1814 | 1815 | /** 1816 | * Shows the InfoBox. [Deprecated; use setVisible instead.] 1817 | */ 1818 | InfoBox.prototype.show = function () { 1819 | 1820 | this.isHidden_ = false; 1821 | if (this.div_) { 1822 | this.div_.style.visibility = "visible"; 1823 | } 1824 | }; 1825 | 1826 | /** 1827 | * Hides the InfoBox. [Deprecated; use setVisible instead.] 1828 | */ 1829 | InfoBox.prototype.hide = function () { 1830 | 1831 | this.isHidden_ = true; 1832 | if (this.div_) { 1833 | this.div_.style.visibility = "hidden"; 1834 | } 1835 | }; 1836 | 1837 | /** 1838 | * Adds the InfoBox to the specified map or Street View panorama. If anchor 1839 | * (usually a google.maps.Marker) is specified, the position 1840 | * of the InfoBox is set to the position of the anchor. If the 1841 | * anchor is dragged to a new location, the InfoBox moves as well. 1842 | * @param {Map|StreetViewPanorama} map 1843 | * @param {MVCObject} [anchor] 1844 | */ 1845 | InfoBox.prototype.open = function (map, anchor) { 1846 | 1847 | var me = this; 1848 | 1849 | if (anchor) { 1850 | 1851 | this.position_ = anchor.getPosition(); 1852 | this.moveListener_ = google.maps.event.addListener(anchor, "position_changed", function () { 1853 | me.setPosition(this.getPosition()); 1854 | }); 1855 | 1856 | this.mapListener_ = google.maps.event.addListener(anchor, "map_changed", function() { 1857 | me.setMap(this.map); 1858 | }); 1859 | } 1860 | 1861 | this.setMap(map); 1862 | 1863 | if (this.div_) { 1864 | 1865 | this.panBox_(); 1866 | } 1867 | }; 1868 | 1869 | /** 1870 | * Removes the InfoBox from the map. 1871 | */ 1872 | InfoBox.prototype.close = function () { 1873 | 1874 | var i; 1875 | 1876 | if (this.closeListener_) { 1877 | 1878 | google.maps.event.removeListener(this.closeListener_); 1879 | this.closeListener_ = null; 1880 | } 1881 | 1882 | if (this.eventListeners_) { 1883 | 1884 | for (i = 0; i < this.eventListeners_.length; i++) { 1885 | 1886 | google.maps.event.removeListener(this.eventListeners_[i]); 1887 | } 1888 | this.eventListeners_ = null; 1889 | } 1890 | 1891 | if (this.moveListener_) { 1892 | 1893 | google.maps.event.removeListener(this.moveListener_); 1894 | this.moveListener_ = null; 1895 | } 1896 | 1897 | if (this.mapListener_) { 1898 | 1899 | google.maps.event.removeListener(this.mapListener_); 1900 | this.mapListener_ = null; 1901 | } 1902 | 1903 | if (this.contextListener_) { 1904 | 1905 | google.maps.event.removeListener(this.contextListener_); 1906 | this.contextListener_ = null; 1907 | } 1908 | 1909 | this.setMap(null); 1910 | }; 1911 | 1912 | 1913 | module.exports = InfoBox; 1914 | 1915 | /***/ } 1916 | /******/ ]) 1917 | }); 1918 | ; --------------------------------------------------------------------------------