betterplace_explorer 0.0.1.pre.alpha2 → 0.0.1.pre.alpha3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a6b15d3d75ccd4b12f6587048b5e8841a55ed6cf
4
- data.tar.gz: 4274a0b47b96e428138624e1baf0094ded474f0f
3
+ metadata.gz: 744007d44908e58afb9c3df1132147d461da05b0
4
+ data.tar.gz: d7a826b8fde7e9b7c20bd3d0f2333dd0f570ff64
5
5
  SHA512:
6
- metadata.gz: 9c29f65a02a527de5c367b909d14e6871cdf1adc010a7fa629d5eaa85835cc9ae7b8e6fe23a06dadeb77333e4cd619d3291e5117dd7aa2314b5506db9d8113de
7
- data.tar.gz: fa69273dea19814f29b3e9286ace0cb381e7c72690cb7f8217fe0f0b4852ce6868f46c48396d94709438fac061d985049929b162d22466d4ea1f7be3b03cc0a5
6
+ metadata.gz: d35926895739173156e4b1dbb6844b427f76b76b0973ea7e2e11a930b4b696059982a186b4f237ba4a81b745b05858353c853ff5bac169cbac972f322ff9e1a9
7
+ data.tar.gz: 90c5334037a76eb768cee703e6300907b16ca3f5899852901120e093ee521c59cbccaf787fbb16a459b21aecaea7e45f3c62a975ed52fdc281c5a73db28bc90f
@@ -78,7 +78,7 @@
78
78
  displayName: 'Explorer',
79
79
  getInitialState: function () {
80
80
  function getInitialState() {
81
- return { records: [] };
81
+ return { records: [], currentBounds: {}, currentPage: 1 };
82
82
  }
83
83
 
84
84
  return getInitialState;
@@ -92,10 +92,17 @@
92
92
  north: parseFloat(this.props.location.query.north),
93
93
  south: parseFloat(this.props.location.query.south)
94
94
  };
95
- this.setState({ records: [], changeBounds: currentBounds });
95
+ this.setState({ currentBounds: currentBounds, changeBounds: currentBounds });
96
96
  } else {
97
- this.load('https://www.betterplace.org/de/api_v4/volunteering?per_page=20');
97
+ var defaultBounds = {
98
+ east: 19.90940093749998,
99
+ north: 61.493695009727325,
100
+ south: 39.728030772041244,
101
+ west: -4.612083437500019
102
+ };
103
+ this.setState({ currentBounds: defaultBounds, changeBounds: defaultBounds });
98
104
  }
105
+ // this.load('https://www.betterplace.org/de/api_v4/volunteering?per_page=20')
99
106
  }
100
107
 
101
108
  return componentDidMount;
@@ -116,8 +123,8 @@
116
123
  'div',
117
124
  { className: 'row' },
118
125
  _react2['default'].createElement(_Pagination2['default'], { currentPage: this.state.currentPage, totalPages: this.state.totalPages, changePage: this.changePage }),
119
- _react2['default'].createElement(_VolunteeringList2['default'], { records: this.state.records, totalEntries: this.state.totalEntries }),
120
- _react2['default'].createElement(_Map2['default'], { records: this.state.records, mapIdle: this.loadByBoundingBox, changeBounds: this.state.changeBounds })
126
+ _react2['default'].createElement(_VolunteeringList2['default'], { records: this.state.records, totalEntries: this.state.totalEntries, setHighlightRecord: this.setHighlightRecord }),
127
+ _react2['default'].createElement(_Map2['default'], { records: this.state.records, mapIdle: this.loadByBoundingBox, changeBounds: this.state.changeBounds, highlightRecord: this.state.highlightRecord })
121
128
  )
122
129
  );
123
130
  }
@@ -141,7 +148,8 @@
141
148
 
142
149
  changePage: function () {
143
150
  function changePage(page) {
144
- this.load('https://www.betterplace.org/de/api_v4/volunteering?per_page=20&page=' + page);
151
+ this.setState({ currentPage: page });
152
+ this.load(this.state.currentBounds, page);
145
153
  }
146
154
 
147
155
  return changePage;
@@ -163,16 +171,28 @@
163
171
  // browserHistory.push({ pathname: `/l/${location}`, query: this.props.location.query })
164
172
 
165
173
  this.updateURLBounds(bounds);
166
- this.setState({ changeBounds: bounds });
174
+ this.setState({ currentBounds: bounds, changeBounds: bounds, currentPage: 1 });
167
175
  }
168
176
 
169
177
  return changeLocation;
170
178
  }(),
171
179
 
172
180
  load: function () {
173
- function load(url) {
181
+ function load(bounds, page) {
174
182
  var _this = this;
175
183
 
184
+ var params = {
185
+ nelat: bounds.north,
186
+ nelng: bounds.east,
187
+ swlat: bounds.south,
188
+ swlng: bounds.west,
189
+ page: page,
190
+ per_page: 20
191
+ };
192
+ var query = Object.keys(params).map(function (k, _) {
193
+ return k + '=' + params[k];
194
+ }).join('&');
195
+ var url = 'https://www.betterplace.org/de/api_v4/volunteering?' + query;
176
196
  fetch(url).then(function (response) {
177
197
  return response.json();
178
198
  }).then(function (json) {
@@ -187,12 +207,20 @@
187
207
 
188
208
  loadByBoundingBox: function () {
189
209
  function loadByBoundingBox(bounds) {
190
- bounds = bounds.toJSON();
210
+ this.setState({ currentBounds: bounds, currentPage: 1 });
191
211
  this.updateURLBounds(bounds);
192
- this.load('https://www.betterplace.org/de/api_v4/volunteering?nelat=' + bounds.north + '&nelng=' + bounds.east + '&swlat=' + bounds.south + '&swlng=' + bounds.west + '&per_page=20');
212
+ this.load(bounds, 1);
193
213
  }
194
214
 
195
215
  return loadByBoundingBox;
216
+ }(),
217
+
218
+ setHighlightRecord: function () {
219
+ function setHighlightRecord(record) {
220
+ this.setState({ highlightRecord: record });
221
+ }
222
+
223
+ return setHighlightRecord;
196
224
  }()
197
225
  });
198
226
 
@@ -26009,13 +26037,15 @@
26009
26037
 
26010
26038
  render: function () {
26011
26039
  function render() {
26040
+ var _this = this;
26041
+
26012
26042
  var volunteeringNodes = this.props.records.map(function (record) {
26013
- return _react2['default'].createElement(_Volunteering2['default'], { record: record, key: record.id });
26043
+ return _react2['default'].createElement(_Volunteering2['default'], { record: record, key: record.id, setHighlightRecord: _this.props.setHighlightRecord });
26014
26044
  });
26015
26045
 
26016
26046
  return _react2['default'].createElement(
26017
26047
  'div',
26018
- { className: 'col-md-14' },
26048
+ { className: 'col-md-14 bpe--volunteering-list' },
26019
26049
  _react2['default'].createElement(
26020
26050
  'h1',
26021
26051
  null,
@@ -26026,7 +26056,7 @@
26026
26056
  ),
26027
26057
  _react2['default'].createElement(
26028
26058
  'div',
26029
- { className: 'bpe--volunteering-list' },
26059
+ null,
26030
26060
  volunteeringNodes
26031
26061
  )
26032
26062
  );
@@ -26059,12 +26089,13 @@
26059
26089
 
26060
26090
  render: function () {
26061
26091
  function render() {
26062
- var imageUrl = this.findLink(this.props.record.image.links, "fill_270x141");
26092
+ var imageUrl = this.findLink(this.props.record.image.links, 'fill_270x141');
26063
26093
  var carrier = this.props.record.carrier || {};
26094
+ var selfUrl = '/volunteering/' + this.props.record.id; // this.findLink(this.props.record.links, 'platform')
26064
26095
 
26065
26096
  return _react2['default'].createElement(
26066
26097
  'a',
26067
- { href: '#' },
26098
+ { href: selfUrl, target: '_blank', onMouseEnter: this.handleMouseEnter, onMouseLeave: this.handleMouseLeave },
26068
26099
  _react2['default'].createElement(
26069
26100
  'div',
26070
26101
  { className: 'bpe--volunteering media' },
@@ -26102,6 +26133,22 @@
26102
26133
  }
26103
26134
 
26104
26135
  return findLink;
26136
+ }(),
26137
+
26138
+ handleMouseEnter: function () {
26139
+ function handleMouseEnter() {
26140
+ this.props.setHighlightRecord(this.props.record);
26141
+ }
26142
+
26143
+ return handleMouseEnter;
26144
+ }(),
26145
+
26146
+ handleMouseLeave: function () {
26147
+ function handleMouseLeave() {
26148
+ this.props.setHighlightRecord(null);
26149
+ }
26150
+
26151
+ return handleMouseLeave;
26105
26152
  }()
26106
26153
  });
26107
26154
 
@@ -26123,8 +26170,21 @@
26123
26170
 
26124
26171
  var _react2 = _interopRequireDefault(_react);
26125
26172
 
26173
+ var _reactDom = __webpack_require__(99);
26174
+
26175
+ var _reactDom2 = _interopRequireDefault(_reactDom);
26176
+
26177
+ var _Volunteering = __webpack_require__(230);
26178
+
26179
+ var _Volunteering2 = _interopRequireDefault(_Volunteering);
26180
+
26126
26181
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
26127
26182
 
26183
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
26184
+
26185
+ __webpack_require__(279);
26186
+
26187
+
26128
26188
  var Map = _react2['default'].createClass({
26129
26189
  displayName: 'Map',
26130
26190
 
@@ -26132,11 +26192,31 @@
26132
26192
  function render() {
26133
26193
  var _this = this;
26134
26194
 
26135
- console.log(this.props);
26136
- // console.log(this.googlemap)
26195
+ var image = {
26196
+ url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAABCFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD26OP39/cAAADPz88AAAAAAAAAAAD9/f3p6ens7Ozt7e2CgoLb29vt7e0nJyeampqZmZns7OwsLCxKSkqZmZkAAADa2tqHh4cwMDDq6uqEhIT+/v4AAABERETPz89HR0cAAADc3Nzb29u2Og+1OA3PfWG4QRi9TSfKb1C1OQ7luqvJb0/25uHcoY325+K3PRTmu6y2PBLfqJa3PRPowrXcoo7BVzPPfmL26OO9Tii2OhDep5Tluar15eD15N/epZK5Qhkx1ZAbAAAAOnRSTlMAAQcCBA4UDwMVKAUWHBMIIi0GDB0rC/7tHp8nGin70NLVWLHXNGhn0zQ+ZiqxWTXQWfsZPJ49H7SyPeI8ZAAAAXFJREFUeAGFk+MaIzEYhZOMbdW2l7Xdte7/TnbTp2628/7N55wDLkDI0xL6h0TzEIJHIEUjl1MFWRZUzkU0BR+fNYZVdNExDEfUFZbR7kIgZVpsEM9Ekn4i4ScjmXjAWuY1AvKIeROtpr4sZl9Xw0/jxc9UMRpjEA/P+Yiz81lv8K1/ojfwsnmbQ6calMnYb9P7P/0bhtP0e5sxqWMB2oqVc9te/47J91wzZtEQF9DYaH096T8wWXejrEbhAkxQ9Yb9J4ZeMWBoCCBi46nPfQKDUk1AEPCu0l72SAG9ZUNxeUBz+rtDn8ghonM0kFQxOSYHjFuiKgEkOP6IHDDyHQEBJBuJFTlglzDk8IDwFnjI2Ysh8ZqRl2viQ83Jh5ofDwWREC8NXpwaf1aB/FmFDwwNT989ff7u6UcRf/d/BfP7JJiT5CqPkvuRrmDJ3Yu2RxTtSfaxaBHLfrTZjGaLX6nCSfbPxul0HowTZr1w84ba/y8wjYohV+qwEQAAAABJRU5ErkJggg==',
26197
+ size: new google.maps.Size(32, 32),
26198
+ origin: new google.maps.Point(0, 0),
26199
+ anchor: new google.maps.Point(16, 16)
26200
+ };
26201
+
26202
+ var highlightImage = {
26203
+ url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAABDlBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADr4eH39/fPz88AAAAAAAAAAADp6ekAAAD9/f3s7Ozt7e3t7e2CgoInJyfb29uZmZmamprs7OyEhISHh4cwMDBKSkr+/v7a2toAAAAsLCzq6uqZmZlEREQAAADPz89HR0cAAADb29vc3NxjGxtSAgJRAABZDAyNWFhUBQVSAQHEqKiBRkaBR0eth4fp39+OWVlWBwfq4OCzkJCuiIhsKCjCpqZaDQ1kHBzr4eHDp6exjIzo3t7CpaXKsbFVBgayjo5TAwPo3d2OWlqAlY+pAAAAOnRSTlMAAQcCBA4UDwMVKAUWHBMIIi0GDB0rC/7tnx4nGtAp+9LV11g0sWdo01lZNT77sSo00GY8GZ49H7K0BXS41QAAAXhJREFUeAGFk/OiG0EYxXdmbSvGdZwytnXr9v1fpJkYi9+/83nOwU4AwBA83MITDADYLQAnoEVLrCCwEm1BAge3zzJJiQpnqqrJKSJFylchANd0KpLIunEnmXTibjYRoXTtHAEYSH6MVlObYX89aS0Gw++pp2iMhAw45kPaeHi0x3+aBxpj+/HBoOGhBq6Rxof0z1XzgtYy/dkgNXxXgNBj5cys0byi+zuTi+kEQAVkKlrsdZs3dHtfo5SMowJkpGq3mne07KcIuS0BIJVI/Wt60H4psRBgjCW+ThteAY3pm2gxGEErn+ZNT+auQhMYL3HxgXfAoMJJPAZZ06l7B9Qdk4UYFNTkxDvgV1IVwgPCW6Ah+wFDojXdwDXRoUbehxrtDgUgm3hpB5wafdaz92c9fyEJcPju9/vvfq9x6Lt9BfPtIJiD5PK3kvuRziPJXYm2fSrSaJ9Ee5J9LPqEZF/vdOr94d/U80n2t8YpFG6NE269UPOG2P8/TQCL+fVhnpUAAAAASUVORK5CYII=',
26204
+ size: new google.maps.Size(32, 32),
26205
+ origin: new google.maps.Point(0, 0),
26206
+ anchor: new google.maps.Point(16, 16)
26207
+ };
26208
+
26209
+ var markers = this.props.records.map(function (record) {
26210
+ return _react2['default'].createElement(_reactGoogleMaps.Marker, {
26211
+ position: { lat: record.latitude, lng: record.longitude },
26212
+ key: record.id,
26213
+ icon: record == _this.props.highlightRecord ? highlightImage : image,
26214
+ zIndex: record == _this.props.highlightRecord ? 10000 : null,
26215
+ onClick: _this.handleMarkerClick.bind(_this, record),
26216
+ customInfo: 'Marker A'
26217
+ });
26218
+ });
26137
26219
 
26138
- // if(this.props.bounds)
26139
- // this.googlemap.fitBounds(this.props.bounds)
26140
26220
  return _react2['default'].createElement(
26141
26221
  'div',
26142
26222
  { className: 'col-md-10' },
@@ -26157,11 +26237,10 @@
26157
26237
  }(),
26158
26238
  defaultZoom: 5,
26159
26239
  defaultCenter: { lat: 52.49928, lng: 13.44944 },
26160
- onIdle: this.idle
26240
+ onIdle: this.idle,
26241
+ onClick: this.handleMapClick
26161
26242
  },
26162
- this.props.records.map(function (record, index) {
26163
- return _react2['default'].createElement(_reactGoogleMaps.Marker, { position: { lat: record.latitude, lng: record.longitude }, key: record.id });
26164
- })
26243
+ markers
26165
26244
  )
26166
26245
  })
26167
26246
  )
@@ -26191,12 +26270,61 @@
26191
26270
  return resize;
26192
26271
  }(),
26193
26272
 
26273
+ // Trigger loading of new API results for the current bounds. Since it triggers
26274
+ // multiple times when `fitBounds` is called, we prevent multiple API calls
26275
+ // by comparing the last loaded bounds with the current ones.
26194
26276
  idle: function () {
26195
26277
  function idle() {
26196
- this.props.mapIdle(this.googlemap.getBounds());
26278
+ if (this.preventReloadOnce) {
26279
+ this.preventReloadOnce = false;
26280
+ return;
26281
+ }
26282
+
26283
+ if (this.infoBubble) this.infoBubble.close();
26284
+
26285
+ var newBounds = JSON.stringify(this.googlemap.getBounds());
26286
+
26287
+ if (this.loadedBounds != newBounds) {
26288
+ this.loadedBounds = newBounds;
26289
+ this.props.mapIdle(this.googlemap.getBounds().toJSON());
26290
+ }
26197
26291
  }
26198
26292
 
26199
26293
  return idle;
26294
+ }(),
26295
+
26296
+ handleMapClick: function () {
26297
+ function handleMapClick() {
26298
+ if (this.infoBubble) this.infoBubble.close();
26299
+ }
26300
+
26301
+ return handleMapClick;
26302
+ }(),
26303
+
26304
+ handleMarkerClick: function () {
26305
+ function handleMarkerClick(record) {
26306
+ var _ref;
26307
+
26308
+ if (this.infoBubble) this.infoBubble.close();
26309
+
26310
+ var div = document.createElement('div');
26311
+ _reactDom2['default'].render(_react2['default'].createElement(_Volunteering2['default'], { record: record, key: record.id }), div);
26312
+
26313
+ this.infoBubble = new InfoBubble((_ref = {
26314
+ content: div,
26315
+ maxWidth: 300,
26316
+ position: new google.maps.LatLng(record.latitude, record.longitude),
26317
+ map: this.googlemap.props.map,
26318
+ borderRadius: 0,
26319
+ shadowStyle: 0,
26320
+ minWidth: 200
26321
+ }, _defineProperty(_ref, 'maxWidth', 300), _defineProperty(_ref, 'minHeight', 200), _defineProperty(_ref, 'maxHeight', 200), _defineProperty(_ref, 'hideCloseButton', true), _defineProperty(_ref, 'padding', 0), _ref));
26322
+
26323
+ this.preventReloadOnce = true;
26324
+ this.infoBubble.open();
26325
+ }
26326
+
26327
+ return handleMarkerClick;
26200
26328
  }()
26201
26329
  });
26202
26330
 
@@ -30630,5 +30758,1790 @@
30630
30758
 
30631
30759
  exports["default"] = Pagination;
30632
30760
 
30761
+ /***/ },
30762
+ /* 279 */
30763
+ /***/ function(module, exports) {
30764
+
30765
+ // ==ClosureCompiler==
30766
+ // @compilation_level ADVANCED_OPTIMIZATIONS
30767
+ // @externs_url https://raw.githubusercontent.com/google/closure-compiler/master/contrib/externs/maps/google_maps_api_v3_16.js
30768
+ // ==/ClosureCompiler==
30769
+
30770
+ /**
30771
+ * @name CSS3 InfoBubble with tabs for Google Maps API V3
30772
+ * @version 0.8
30773
+ * @author Luke Mahe
30774
+ * @fileoverview
30775
+ * This library is a CSS Infobubble with tabs. It uses css3 rounded corners and
30776
+ * drop shadows and animations. It also allows tabs
30777
+ */
30778
+
30779
+ /*
30780
+ * Licensed under the Apache License, Version 2.0 (the "License");
30781
+ * you may not use this file except in compliance with the License.
30782
+ * You may obtain a copy of the License at
30783
+ *
30784
+ * http://www.apache.org/licenses/LICENSE-2.0
30785
+ *
30786
+ * Unless required by applicable law or agreed to in writing, software
30787
+ * distributed under the License is distributed on an "AS IS" BASIS,
30788
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30789
+ * See the License for the specific language governing permissions and
30790
+ * limitations under the License.
30791
+ */
30792
+
30793
+
30794
+ /**
30795
+ * A CSS3 InfoBubble v0.8
30796
+ * @param {Object.<string, *>=} opt_options Optional properties to set.
30797
+ * @extends {google.maps.OverlayView}
30798
+ * @constructor
30799
+ */
30800
+ function InfoBubble(opt_options) {
30801
+ this.extend(InfoBubble, google.maps.OverlayView);
30802
+ this.tabs_ = [];
30803
+ this.activeTab_ = null;
30804
+ this.baseZIndex_ = 100;
30805
+ this.isOpen_ = false;
30806
+
30807
+ var options = opt_options || {};
30808
+
30809
+ if (options['backgroundColor'] == undefined) {
30810
+ options['backgroundColor'] = this.BACKGROUND_COLOR_;
30811
+ }
30812
+
30813
+ if (options['borderColor'] == undefined) {
30814
+ options['borderColor'] = this.BORDER_COLOR_;
30815
+ }
30816
+
30817
+ if (options['borderRadius'] == undefined) {
30818
+ options['borderRadius'] = this.BORDER_RADIUS_;
30819
+ }
30820
+
30821
+ if (options['borderWidth'] == undefined) {
30822
+ options['borderWidth'] = this.BORDER_WIDTH_;
30823
+ }
30824
+
30825
+ if (options['padding'] == undefined) {
30826
+ options['padding'] = this.PADDING_;
30827
+ }
30828
+
30829
+ if (options['arrowPosition'] == undefined) {
30830
+ options['arrowPosition'] = this.ARROW_POSITION_;
30831
+ }
30832
+
30833
+ if (options['disableAutoPan'] == undefined) {
30834
+ options['disableAutoPan'] = false;
30835
+ }
30836
+
30837
+ if (options['disableAnimation'] == undefined) {
30838
+ options['disableAnimation'] = false;
30839
+ }
30840
+
30841
+ if (options['minWidth'] == undefined) {
30842
+ options['minWidth'] = this.MIN_WIDTH_;
30843
+ }
30844
+
30845
+ if (options['shadowStyle'] == undefined) {
30846
+ options['shadowStyle'] = this.SHADOW_STYLE_;
30847
+ }
30848
+
30849
+ if (options['arrowSize'] == undefined) {
30850
+ options['arrowSize'] = this.ARROW_SIZE_;
30851
+ }
30852
+
30853
+ if (options['arrowStyle'] == undefined) {
30854
+ options['arrowStyle'] = this.ARROW_STYLE_;
30855
+ }
30856
+
30857
+ if (options['closeSrc'] == undefined) {
30858
+ options['closeSrc'] = this.CLOSE_SRC_;
30859
+ }
30860
+
30861
+ this.buildDom_();
30862
+ this.setValues(options);
30863
+ }
30864
+ window['InfoBubble'] = InfoBubble;
30865
+
30866
+
30867
+ /**
30868
+ * Default arrow size
30869
+ * @const
30870
+ * @private
30871
+ */
30872
+ InfoBubble.prototype.ARROW_SIZE_ = 15;
30873
+
30874
+
30875
+ /**
30876
+ * Default arrow style
30877
+ * @const
30878
+ * @private
30879
+ */
30880
+ InfoBubble.prototype.ARROW_STYLE_ = 0;
30881
+
30882
+
30883
+ /**
30884
+ * Default shadow style
30885
+ * @const
30886
+ * @private
30887
+ */
30888
+ InfoBubble.prototype.SHADOW_STYLE_ = 1;
30889
+
30890
+
30891
+ /**
30892
+ * Default min width
30893
+ * @const
30894
+ * @private
30895
+ */
30896
+ InfoBubble.prototype.MIN_WIDTH_ = 50;
30897
+
30898
+
30899
+ /**
30900
+ * Default arrow position
30901
+ * @const
30902
+ * @private
30903
+ */
30904
+ InfoBubble.prototype.ARROW_POSITION_ = 50;
30905
+
30906
+
30907
+ /**
30908
+ * Default padding
30909
+ * @const
30910
+ * @private
30911
+ */
30912
+ InfoBubble.prototype.PADDING_ = 10;
30913
+
30914
+
30915
+ /**
30916
+ * Default border width
30917
+ * @const
30918
+ * @private
30919
+ */
30920
+ InfoBubble.prototype.BORDER_WIDTH_ = 1;
30921
+
30922
+
30923
+ /**
30924
+ * Default border color
30925
+ * @const
30926
+ * @private
30927
+ */
30928
+ InfoBubble.prototype.BORDER_COLOR_ = '#ccc';
30929
+
30930
+
30931
+ /**
30932
+ * Default border radius
30933
+ * @const
30934
+ * @private
30935
+ */
30936
+ InfoBubble.prototype.BORDER_RADIUS_ = 10;
30937
+
30938
+
30939
+ /**
30940
+ * Default background color
30941
+ * @const
30942
+ * @private
30943
+ */
30944
+ InfoBubble.prototype.BACKGROUND_COLOR_ = '#fff';
30945
+
30946
+ /**
30947
+ * Default close image source
30948
+ * @const
30949
+ * @private
30950
+ */
30951
+ InfoBubble.prototype.CLOSE_SRC_ = 'https://maps.gstatic.com/intl/en_us/mapfiles/iw_close.gif';
30952
+
30953
+ /**
30954
+ * Extends a objects prototype by anothers.
30955
+ *
30956
+ * @param {Object} obj1 The object to be extended.
30957
+ * @param {Object} obj2 The object to extend with.
30958
+ * @return {Object} The new extended object.
30959
+ * @ignore
30960
+ */
30961
+ InfoBubble.prototype.extend = function(obj1, obj2) {
30962
+ return (function(object) {
30963
+ for (var property in object.prototype) {
30964
+ this.prototype[property] = object.prototype[property];
30965
+ }
30966
+ return this;
30967
+ }).apply(obj1, [obj2]);
30968
+ };
30969
+
30970
+
30971
+ /**
30972
+ * Builds the InfoBubble dom
30973
+ * @private
30974
+ */
30975
+ InfoBubble.prototype.buildDom_ = function() {
30976
+ var bubble = this.bubble_ = document.createElement('DIV');
30977
+ bubble.style['position'] = 'absolute';
30978
+ bubble.style['zIndex'] = this.baseZIndex_;
30979
+
30980
+ var tabsContainer = this.tabsContainer_ = document.createElement('DIV');
30981
+ tabsContainer.style['position'] = 'relative';
30982
+
30983
+ // Close button
30984
+ var close = this.close_ = document.createElement('IMG');
30985
+ close.style['position'] = 'absolute';
30986
+ close.style['border'] = 0;
30987
+ close.style['zIndex'] = this.baseZIndex_ + 1;
30988
+ close.style['cursor'] = 'pointer';
30989
+ close.src = this.get('closeSrc');
30990
+
30991
+ var that = this;
30992
+ google.maps.event.addDomListener(close, 'click', function() {
30993
+ that.close();
30994
+ google.maps.event.trigger(that, 'closeclick');
30995
+ });
30996
+
30997
+ // Content area
30998
+ var contentContainer = this.contentContainer_ = document.createElement('DIV');
30999
+ contentContainer.style['overflowX'] = 'auto';
31000
+ contentContainer.style['overflowY'] = 'auto';
31001
+ contentContainer.style['cursor'] = 'default';
31002
+ contentContainer.style['clear'] = 'both';
31003
+ contentContainer.style['position'] = 'relative';
31004
+
31005
+ var content = this.content_ = document.createElement('DIV');
31006
+ contentContainer.appendChild(content);
31007
+
31008
+ // Arrow
31009
+ var arrow = this.arrow_ = document.createElement('DIV');
31010
+ arrow.style['position'] = 'relative';
31011
+
31012
+ var arrowOuter = this.arrowOuter_ = document.createElement('DIV');
31013
+ var arrowInner = this.arrowInner_ = document.createElement('DIV');
31014
+
31015
+ var arrowSize = this.getArrowSize_();
31016
+
31017
+ arrowOuter.style['position'] = arrowInner.style['position'] = 'absolute';
31018
+ arrowOuter.style['left'] = arrowInner.style['left'] = '50%';
31019
+ arrowOuter.style['height'] = arrowInner.style['height'] = '0';
31020
+ arrowOuter.style['width'] = arrowInner.style['width'] = '0';
31021
+ arrowOuter.style['marginLeft'] = this.px(-arrowSize);
31022
+ arrowOuter.style['borderWidth'] = this.px(arrowSize);
31023
+ arrowOuter.style['borderBottomWidth'] = 0;
31024
+
31025
+ // Shadow
31026
+ var bubbleShadow = this.bubbleShadow_ = document.createElement('DIV');
31027
+ bubbleShadow.style['position'] = 'absolute';
31028
+
31029
+ // Hide the InfoBubble by default
31030
+ bubble.style['display'] = bubbleShadow.style['display'] = 'none';
31031
+
31032
+ bubble.appendChild(this.tabsContainer_);
31033
+ bubble.appendChild(close);
31034
+ bubble.appendChild(contentContainer);
31035
+ arrow.appendChild(arrowOuter);
31036
+ arrow.appendChild(arrowInner);
31037
+ bubble.appendChild(arrow);
31038
+
31039
+ var stylesheet = document.createElement('style');
31040
+ stylesheet.setAttribute('type', 'text/css');
31041
+
31042
+ /**
31043
+ * The animation for the infobubble
31044
+ * @type {string}
31045
+ */
31046
+ this.animationName_ = '_ibani_' + Math.round(Math.random() * 10000);
31047
+
31048
+ var css = '.' + this.animationName_ + '{-webkit-animation-name:' +
31049
+ this.animationName_ + ';-webkit-animation-duration:0.5s;' +
31050
+ '-webkit-animation-iteration-count:1;}' +
31051
+ '@-webkit-keyframes ' + this.animationName_ + ' {from {' +
31052
+ '-webkit-transform: scale(0)}50% {-webkit-transform: scale(1.2)}90% ' +
31053
+ '{-webkit-transform: scale(0.95)}to {-webkit-transform: scale(1)}}';
31054
+
31055
+ stylesheet.textContent = css;
31056
+ document.getElementsByTagName('head')[0].appendChild(stylesheet);
31057
+ };
31058
+
31059
+
31060
+ /**
31061
+ * Sets the background class name
31062
+ *
31063
+ * @param {string} className The class name to set.
31064
+ */
31065
+ InfoBubble.prototype.setBackgroundClassName = function(className) {
31066
+ this.set('backgroundClassName', className);
31067
+ };
31068
+ InfoBubble.prototype['setBackgroundClassName'] = InfoBubble.prototype.setBackgroundClassName;
31069
+
31070
+
31071
+ /**
31072
+ * changed MVC callback
31073
+ */
31074
+ InfoBubble.prototype.backgroundClassName_changed = function() {
31075
+ this.content_.className = this.get('backgroundClassName');
31076
+ };
31077
+ InfoBubble.prototype['backgroundClassName_changed'] = InfoBubble.prototype.backgroundClassName_changed;
31078
+
31079
+
31080
+ /**
31081
+ * Sets the class of the tab
31082
+ *
31083
+ * @param {string} className the class name to set.
31084
+ */
31085
+ InfoBubble.prototype.setTabClassName = function(className) {
31086
+ this.set('tabClassName', className);
31087
+ };
31088
+ InfoBubble.prototype['setTabClassName'] = InfoBubble.prototype.setTabClassName;
31089
+
31090
+
31091
+ /**
31092
+ * tabClassName changed MVC callback
31093
+ */
31094
+ InfoBubble.prototype.tabClassName_changed = function() {
31095
+ this.updateTabStyles_();
31096
+ };
31097
+ InfoBubble.prototype['tabClassName_changed'] = InfoBubble.prototype.tabClassName_changed;
31098
+
31099
+
31100
+ /**
31101
+ * Gets the style of the arrow
31102
+ *
31103
+ * @private
31104
+ * @return {number} The style of the arrow.
31105
+ */
31106
+ InfoBubble.prototype.getArrowStyle_ = function() {
31107
+ return parseInt(this.get('arrowStyle'), 10) || 0;
31108
+ };
31109
+
31110
+
31111
+ /**
31112
+ * Sets the style of the arrow
31113
+ *
31114
+ * @param {number} style The style of the arrow.
31115
+ */
31116
+ InfoBubble.prototype.setArrowStyle = function(style) {
31117
+ this.set('arrowStyle', style);
31118
+ };
31119
+ InfoBubble.prototype['setArrowStyle'] = InfoBubble.prototype.setArrowStyle;
31120
+
31121
+
31122
+ /**
31123
+ * Arrow style changed MVC callback
31124
+ */
31125
+ InfoBubble.prototype.arrowStyle_changed = function() {
31126
+ this.arrowSize_changed();
31127
+ };
31128
+ InfoBubble.prototype['arrowStyle_changed'] = InfoBubble.prototype.arrowStyle_changed;
31129
+
31130
+
31131
+ /**
31132
+ * Gets the size of the arrow
31133
+ *
31134
+ * @private
31135
+ * @return {number} The size of the arrow.
31136
+ */
31137
+ InfoBubble.prototype.getArrowSize_ = function() {
31138
+ return parseInt(this.get('arrowSize'), 10) || 0;
31139
+ };
31140
+
31141
+
31142
+ /**
31143
+ * Sets the size of the arrow
31144
+ *
31145
+ * @param {number} size The size of the arrow.
31146
+ */
31147
+ InfoBubble.prototype.setArrowSize = function(size) {
31148
+ this.set('arrowSize', size);
31149
+ };
31150
+ InfoBubble.prototype['setArrowSize'] = InfoBubble.prototype.setArrowSize;
31151
+
31152
+
31153
+ /**
31154
+ * Arrow size changed MVC callback
31155
+ */
31156
+ InfoBubble.prototype.arrowSize_changed = function() {
31157
+ this.borderWidth_changed();
31158
+ };
31159
+ InfoBubble.prototype['arrowSize_changed'] = InfoBubble.prototype.arrowSize_changed;
31160
+
31161
+
31162
+ /**
31163
+ * Set the position of the InfoBubble arrow
31164
+ *
31165
+ * @param {number} pos The position to set.
31166
+ */
31167
+ InfoBubble.prototype.setArrowPosition = function(pos) {
31168
+ this.set('arrowPosition', pos);
31169
+ };
31170
+ InfoBubble.prototype['setArrowPosition'] = InfoBubble.prototype.setArrowPosition;
31171
+
31172
+
31173
+ /**
31174
+ * Get the position of the InfoBubble arrow
31175
+ *
31176
+ * @private
31177
+ * @return {number} The position..
31178
+ */
31179
+ InfoBubble.prototype.getArrowPosition_ = function() {
31180
+ return parseInt(this.get('arrowPosition'), 10) || 0;
31181
+ };
31182
+
31183
+
31184
+ /**
31185
+ * arrowPosition changed MVC callback
31186
+ */
31187
+ InfoBubble.prototype.arrowPosition_changed = function() {
31188
+ var pos = this.getArrowPosition_();
31189
+ this.arrowOuter_.style['left'] = this.arrowInner_.style['left'] = pos + '%';
31190
+
31191
+ this.redraw_();
31192
+ };
31193
+ InfoBubble.prototype['arrowPosition_changed'] = InfoBubble.prototype.arrowPosition_changed;
31194
+
31195
+
31196
+ /**
31197
+ * Set the zIndex of the InfoBubble
31198
+ *
31199
+ * @param {number} zIndex The zIndex to set.
31200
+ */
31201
+ InfoBubble.prototype.setZIndex = function(zIndex) {
31202
+ this.set('zIndex', zIndex);
31203
+ };
31204
+ InfoBubble.prototype['setZIndex'] = InfoBubble.prototype.setZIndex;
31205
+
31206
+
31207
+ /**
31208
+ * Get the zIndex of the InfoBubble
31209
+ *
31210
+ * @return {number} The zIndex to set.
31211
+ */
31212
+ InfoBubble.prototype.getZIndex = function() {
31213
+ return parseInt(this.get('zIndex'), 10) || this.baseZIndex_;
31214
+ };
31215
+
31216
+
31217
+ /**
31218
+ * zIndex changed MVC callback
31219
+ */
31220
+ InfoBubble.prototype.zIndex_changed = function() {
31221
+ var zIndex = this.getZIndex();
31222
+
31223
+ this.bubble_.style['zIndex'] = this.baseZIndex_ = zIndex;
31224
+ this.close_.style['zIndex'] = zIndex + 1;
31225
+ };
31226
+ InfoBubble.prototype['zIndex_changed'] = InfoBubble.prototype.zIndex_changed;
31227
+
31228
+
31229
+ /**
31230
+ * Set the style of the shadow
31231
+ *
31232
+ * @param {number} shadowStyle The style of the shadow.
31233
+ */
31234
+ InfoBubble.prototype.setShadowStyle = function(shadowStyle) {
31235
+ this.set('shadowStyle', shadowStyle);
31236
+ };
31237
+ InfoBubble.prototype['setShadowStyle'] = InfoBubble.prototype.setShadowStyle;
31238
+
31239
+
31240
+ /**
31241
+ * Get the style of the shadow
31242
+ *
31243
+ * @private
31244
+ * @return {number} The style of the shadow.
31245
+ */
31246
+ InfoBubble.prototype.getShadowStyle_ = function() {
31247
+ return parseInt(this.get('shadowStyle'), 10) || 0;
31248
+ };
31249
+
31250
+
31251
+ /**
31252
+ * shadowStyle changed MVC callback
31253
+ */
31254
+ InfoBubble.prototype.shadowStyle_changed = function() {
31255
+ var shadowStyle = this.getShadowStyle_();
31256
+
31257
+ var display = '';
31258
+ var shadow = '';
31259
+ var backgroundColor = '';
31260
+ switch (shadowStyle) {
31261
+ case 0:
31262
+ display = 'none';
31263
+ break;
31264
+ case 1:
31265
+ shadow = '40px 15px 10px rgba(33,33,33,0.3)';
31266
+ backgroundColor = 'transparent';
31267
+ break;
31268
+ case 2:
31269
+ shadow = '0 0 2px rgba(33,33,33,0.3)';
31270
+ backgroundColor = 'rgba(33,33,33,0.35)';
31271
+ break;
31272
+ }
31273
+ this.bubbleShadow_.style['boxShadow'] =
31274
+ this.bubbleShadow_.style['webkitBoxShadow'] =
31275
+ this.bubbleShadow_.style['MozBoxShadow'] = shadow;
31276
+ this.bubbleShadow_.style['backgroundColor'] = backgroundColor;
31277
+ if (this.isOpen_) {
31278
+ this.bubbleShadow_.style['display'] = display;
31279
+ this.draw();
31280
+ }
31281
+ };
31282
+ InfoBubble.prototype['shadowStyle_changed'] = InfoBubble.prototype.shadowStyle_changed;
31283
+
31284
+
31285
+ /**
31286
+ * Show the close button
31287
+ */
31288
+ InfoBubble.prototype.showCloseButton = function() {
31289
+ this.set('hideCloseButton', false);
31290
+ };
31291
+ InfoBubble.prototype['showCloseButton'] = InfoBubble.prototype.showCloseButton;
31292
+
31293
+
31294
+ /**
31295
+ * Hide the close button
31296
+ */
31297
+ InfoBubble.prototype.hideCloseButton = function() {
31298
+ this.set('hideCloseButton', true);
31299
+ };
31300
+ InfoBubble.prototype['hideCloseButton'] = InfoBubble.prototype.hideCloseButton;
31301
+
31302
+
31303
+ /**
31304
+ * hideCloseButton changed MVC callback
31305
+ */
31306
+ InfoBubble.prototype.hideCloseButton_changed = function() {
31307
+ this.close_.style['display'] = this.get('hideCloseButton') ? 'none' : '';
31308
+ };
31309
+ InfoBubble.prototype['hideCloseButton_changed'] = InfoBubble.prototype.hideCloseButton_changed;
31310
+
31311
+
31312
+ /**
31313
+ * Set the background color
31314
+ *
31315
+ * @param {string} color The color to set.
31316
+ */
31317
+ InfoBubble.prototype.setBackgroundColor = function(color) {
31318
+ if (color) {
31319
+ this.set('backgroundColor', color);
31320
+ }
31321
+ };
31322
+ InfoBubble.prototype['setBackgroundColor'] = InfoBubble.prototype.setBackgroundColor;
31323
+
31324
+
31325
+ /**
31326
+ * backgroundColor changed MVC callback
31327
+ */
31328
+ InfoBubble.prototype.backgroundColor_changed = function() {
31329
+ var backgroundColor = this.get('backgroundColor');
31330
+ this.contentContainer_.style['backgroundColor'] = backgroundColor;
31331
+
31332
+ this.arrowInner_.style['borderColor'] = backgroundColor +
31333
+ ' transparent transparent';
31334
+ this.updateTabStyles_();
31335
+ };
31336
+ InfoBubble.prototype['backgroundColor_changed'] = InfoBubble.prototype.backgroundColor_changed;
31337
+
31338
+
31339
+ /**
31340
+ * Set the border color
31341
+ *
31342
+ * @param {string} color The border color.
31343
+ */
31344
+ InfoBubble.prototype.setBorderColor = function(color) {
31345
+ if (color) {
31346
+ this.set('borderColor', color);
31347
+ }
31348
+ };
31349
+ InfoBubble.prototype['setBorderColor'] = InfoBubble.prototype.setBorderColor;
31350
+
31351
+
31352
+ /**
31353
+ * borderColor changed MVC callback
31354
+ */
31355
+ InfoBubble.prototype.borderColor_changed = function() {
31356
+ var borderColor = this.get('borderColor');
31357
+
31358
+ var contentContainer = this.contentContainer_;
31359
+ var arrowOuter = this.arrowOuter_;
31360
+ contentContainer.style['borderColor'] = borderColor;
31361
+
31362
+ arrowOuter.style['borderColor'] = borderColor +
31363
+ ' transparent transparent';
31364
+
31365
+ contentContainer.style['borderStyle'] =
31366
+ arrowOuter.style['borderStyle'] =
31367
+ this.arrowInner_.style['borderStyle'] = 'solid';
31368
+
31369
+ this.updateTabStyles_();
31370
+ };
31371
+ InfoBubble.prototype['borderColor_changed'] = InfoBubble.prototype.borderColor_changed;
31372
+
31373
+
31374
+ /**
31375
+ * Set the radius of the border
31376
+ *
31377
+ * @param {number} radius The radius of the border.
31378
+ */
31379
+ InfoBubble.prototype.setBorderRadius = function(radius) {
31380
+ this.set('borderRadius', radius);
31381
+ };
31382
+ InfoBubble.prototype['setBorderRadius'] = InfoBubble.prototype.setBorderRadius;
31383
+
31384
+
31385
+ /**
31386
+ * Get the radius of the border
31387
+ *
31388
+ * @private
31389
+ * @return {number} The radius of the border.
31390
+ */
31391
+ InfoBubble.prototype.getBorderRadius_ = function() {
31392
+ return parseInt(this.get('borderRadius'), 10) || 0;
31393
+ };
31394
+
31395
+
31396
+ /**
31397
+ * borderRadius changed MVC callback
31398
+ */
31399
+ InfoBubble.prototype.borderRadius_changed = function() {
31400
+ var borderRadius = this.getBorderRadius_();
31401
+ var borderWidth = this.getBorderWidth_();
31402
+
31403
+ this.contentContainer_.style['borderRadius'] =
31404
+ this.contentContainer_.style['MozBorderRadius'] =
31405
+ this.contentContainer_.style['webkitBorderRadius'] =
31406
+ this.bubbleShadow_.style['borderRadius'] =
31407
+ this.bubbleShadow_.style['MozBorderRadius'] =
31408
+ this.bubbleShadow_.style['webkitBorderRadius'] = this.px(borderRadius);
31409
+
31410
+ this.tabsContainer_.style['paddingLeft'] =
31411
+ this.tabsContainer_.style['paddingRight'] =
31412
+ this.px(borderRadius + borderWidth);
31413
+
31414
+ this.redraw_();
31415
+ };
31416
+ InfoBubble.prototype['borderRadius_changed'] = InfoBubble.prototype.borderRadius_changed;
31417
+
31418
+
31419
+ /**
31420
+ * Get the width of the border
31421
+ *
31422
+ * @private
31423
+ * @return {number} width The width of the border.
31424
+ */
31425
+ InfoBubble.prototype.getBorderWidth_ = function() {
31426
+ return parseInt(this.get('borderWidth'), 10) || 0;
31427
+ };
31428
+
31429
+
31430
+ /**
31431
+ * Set the width of the border
31432
+ *
31433
+ * @param {number} width The width of the border.
31434
+ */
31435
+ InfoBubble.prototype.setBorderWidth = function(width) {
31436
+ this.set('borderWidth', width);
31437
+ };
31438
+ InfoBubble.prototype['setBorderWidth'] = InfoBubble.prototype.setBorderWidth;
31439
+
31440
+
31441
+ /**
31442
+ * borderWidth change MVC callback
31443
+ */
31444
+ InfoBubble.prototype.borderWidth_changed = function() {
31445
+ var borderWidth = this.getBorderWidth_();
31446
+
31447
+ this.contentContainer_.style['borderWidth'] = this.px(borderWidth);
31448
+ this.tabsContainer_.style['top'] = this.px(borderWidth);
31449
+
31450
+ this.updateArrowStyle_();
31451
+ this.updateTabStyles_();
31452
+ this.borderRadius_changed();
31453
+ this.redraw_();
31454
+ };
31455
+ InfoBubble.prototype['borderWidth_changed'] = InfoBubble.prototype.borderWidth_changed;
31456
+
31457
+
31458
+ /**
31459
+ * Update the arrow style
31460
+ * @private
31461
+ */
31462
+ InfoBubble.prototype.updateArrowStyle_ = function() {
31463
+ var borderWidth = this.getBorderWidth_();
31464
+ var arrowSize = this.getArrowSize_();
31465
+ var arrowStyle = this.getArrowStyle_();
31466
+ var arrowOuterSizePx = this.px(arrowSize);
31467
+ var arrowInnerSizePx = this.px(Math.max(0, arrowSize - borderWidth));
31468
+
31469
+ var outer = this.arrowOuter_;
31470
+ var inner = this.arrowInner_;
31471
+
31472
+ this.arrow_.style['marginTop'] = this.px(-borderWidth);
31473
+ outer.style['borderTopWidth'] = arrowOuterSizePx;
31474
+ inner.style['borderTopWidth'] = arrowInnerSizePx;
31475
+
31476
+ // Full arrow or arrow pointing to the left
31477
+ if (arrowStyle == 0 || arrowStyle == 1) {
31478
+ outer.style['borderLeftWidth'] = arrowOuterSizePx;
31479
+ inner.style['borderLeftWidth'] = arrowInnerSizePx;
31480
+ } else {
31481
+ outer.style['borderLeftWidth'] = inner.style['borderLeftWidth'] = 0;
31482
+ }
31483
+
31484
+ // Full arrow or arrow pointing to the right
31485
+ if (arrowStyle == 0 || arrowStyle == 2) {
31486
+ outer.style['borderRightWidth'] = arrowOuterSizePx;
31487
+ inner.style['borderRightWidth'] = arrowInnerSizePx;
31488
+ } else {
31489
+ outer.style['borderRightWidth'] = inner.style['borderRightWidth'] = 0;
31490
+ }
31491
+
31492
+ if (arrowStyle < 2) {
31493
+ outer.style['marginLeft'] = this.px(-(arrowSize));
31494
+ inner.style['marginLeft'] = this.px(-(arrowSize - borderWidth));
31495
+ } else {
31496
+ outer.style['marginLeft'] = inner.style['marginLeft'] = 0;
31497
+ }
31498
+
31499
+ // If there is no border then don't show thw outer arrow
31500
+ if (borderWidth == 0) {
31501
+ outer.style['display'] = 'none';
31502
+ } else {
31503
+ outer.style['display'] = '';
31504
+ }
31505
+ };
31506
+
31507
+
31508
+ /**
31509
+ * Set the padding of the InfoBubble
31510
+ *
31511
+ * @param {number} padding The padding to apply.
31512
+ */
31513
+ InfoBubble.prototype.setPadding = function(padding) {
31514
+ this.set('padding', padding);
31515
+ };
31516
+ InfoBubble.prototype['setPadding'] = InfoBubble.prototype.setPadding;
31517
+
31518
+
31519
+ /**
31520
+ * Set the close image url
31521
+ *
31522
+ * @param {string} src The url of the image used as a close icon
31523
+ */
31524
+ InfoBubble.prototype.setCloseSrc = function(src) {
31525
+ if (src && this.close_) {
31526
+ this.close_.src = src;
31527
+ }
31528
+ };
31529
+ InfoBubble.prototype['setCloseSrc'] = InfoBubble.prototype.setCloseSrc;
31530
+
31531
+
31532
+ /**
31533
+ * Set the padding of the InfoBubble
31534
+ *
31535
+ * @private
31536
+ * @return {number} padding The padding to apply.
31537
+ */
31538
+ InfoBubble.prototype.getPadding_ = function() {
31539
+ return parseInt(this.get('padding'), 10) || 0;
31540
+ };
31541
+
31542
+
31543
+ /**
31544
+ * padding changed MVC callback
31545
+ */
31546
+ InfoBubble.prototype.padding_changed = function() {
31547
+ var padding = this.getPadding_();
31548
+ this.contentContainer_.style['padding'] = this.px(padding);
31549
+ this.updateTabStyles_();
31550
+
31551
+ this.redraw_();
31552
+ };
31553
+ InfoBubble.prototype['padding_changed'] = InfoBubble.prototype.padding_changed;
31554
+
31555
+
31556
+ /**
31557
+ * Add px extention to the number
31558
+ *
31559
+ * @param {number} num The number to wrap.
31560
+ * @return {string|number} A wrapped number.
31561
+ */
31562
+ InfoBubble.prototype.px = function(num) {
31563
+ if (num) {
31564
+ // 0 doesn't need to be wrapped
31565
+ return num + 'px';
31566
+ }
31567
+ return num;
31568
+ };
31569
+
31570
+
31571
+ /**
31572
+ * Add events to stop propagation
31573
+ * @private
31574
+ */
31575
+ InfoBubble.prototype.addEvents_ = function() {
31576
+ // We want to cancel all the events so they do not go to the map
31577
+ var events = ['mousedown', 'mousemove', 'mouseover', 'mouseout', 'mouseup',
31578
+ 'mousewheel', 'DOMMouseScroll', 'touchstart', 'touchend', 'touchmove',
31579
+ 'dblclick', 'contextmenu', 'click'];
31580
+
31581
+ var bubble = this.bubble_;
31582
+ this.listeners_ = [];
31583
+ for (var i = 0, event; event = events[i]; i++) {
31584
+ this.listeners_.push(
31585
+ google.maps.event.addDomListener(bubble, event, function(e) {
31586
+ e.cancelBubble = true;
31587
+ if (e.stopPropagation) {
31588
+ e.stopPropagation();
31589
+ }
31590
+ })
31591
+ );
31592
+ }
31593
+ };
31594
+
31595
+
31596
+ /**
31597
+ * On Adding the InfoBubble to a map
31598
+ * Implementing the OverlayView interface
31599
+ */
31600
+ InfoBubble.prototype.onAdd = function() {
31601
+ if (!this.bubble_) {
31602
+ this.buildDom_();
31603
+ }
31604
+
31605
+ this.addEvents_();
31606
+
31607
+ var panes = this.getPanes();
31608
+ if (panes) {
31609
+ panes.floatPane.appendChild(this.bubble_);
31610
+ panes.floatShadow.appendChild(this.bubbleShadow_);
31611
+ }
31612
+
31613
+ /* once the infoBubble has been added to the DOM, fire 'domready' event */
31614
+ google.maps.event.trigger(this, 'domready');
31615
+ };
31616
+ InfoBubble.prototype['onAdd'] = InfoBubble.prototype.onAdd;
31617
+
31618
+
31619
+ /**
31620
+ * Draw the InfoBubble
31621
+ * Implementing the OverlayView interface
31622
+ */
31623
+ InfoBubble.prototype.draw = function() {
31624
+ var projection = this.getProjection();
31625
+
31626
+ if (!projection) {
31627
+ // The map projection is not ready yet so do nothing
31628
+ return;
31629
+ }
31630
+
31631
+ var latLng = /** @type {google.maps.LatLng} */ (this.get('position'));
31632
+
31633
+ if (!latLng) {
31634
+ this.close();
31635
+ return;
31636
+ }
31637
+
31638
+ var tabHeight = 0;
31639
+
31640
+ if (this.activeTab_) {
31641
+ tabHeight = this.activeTab_.offsetHeight;
31642
+ }
31643
+
31644
+ var anchorHeight = this.getAnchorHeight_();
31645
+ var arrowSize = this.getArrowSize_();
31646
+ var arrowPosition = this.getArrowPosition_();
31647
+
31648
+ arrowPosition = arrowPosition / 100;
31649
+
31650
+ var pos = projection.fromLatLngToDivPixel(latLng);
31651
+ var width = this.contentContainer_.offsetWidth;
31652
+ var height = this.bubble_.offsetHeight;
31653
+
31654
+ if (!width) {
31655
+ return;
31656
+ }
31657
+
31658
+ // Adjust for the height of the info bubble
31659
+ var top = pos.y - (height + arrowSize);
31660
+
31661
+ if (anchorHeight) {
31662
+ // If there is an anchor then include the height
31663
+ top -= anchorHeight;
31664
+ }
31665
+
31666
+ var left = pos.x - (width * arrowPosition);
31667
+
31668
+ this.bubble_.style['top'] = this.px(top);
31669
+ this.bubble_.style['left'] = this.px(left);
31670
+
31671
+ var shadowStyle = parseInt(this.get('shadowStyle'), 10);
31672
+
31673
+ switch (shadowStyle) {
31674
+ case 1:
31675
+ // Shadow is behind
31676
+ this.bubbleShadow_.style['top'] = this.px(top + tabHeight - 1);
31677
+ this.bubbleShadow_.style['left'] = this.px(left);
31678
+ this.bubbleShadow_.style['width'] = this.px(width);
31679
+ this.bubbleShadow_.style['height'] =
31680
+ this.px(this.contentContainer_.offsetHeight - arrowSize);
31681
+ break;
31682
+ case 2:
31683
+ // Shadow is below
31684
+ width = width * 0.8;
31685
+ if (anchorHeight) {
31686
+ this.bubbleShadow_.style['top'] = this.px(pos.y);
31687
+ } else {
31688
+ this.bubbleShadow_.style['top'] = this.px(pos.y + arrowSize);
31689
+ }
31690
+ this.bubbleShadow_.style['left'] = this.px(pos.x - width * arrowPosition);
31691
+
31692
+ this.bubbleShadow_.style['width'] = this.px(width);
31693
+ this.bubbleShadow_.style['height'] = this.px(2);
31694
+ break;
31695
+ }
31696
+ };
31697
+ InfoBubble.prototype['draw'] = InfoBubble.prototype.draw;
31698
+
31699
+
31700
+ /**
31701
+ * Removing the InfoBubble from a map
31702
+ */
31703
+ InfoBubble.prototype.onRemove = function() {
31704
+ if (this.bubble_ && this.bubble_.parentNode) {
31705
+ this.bubble_.parentNode.removeChild(this.bubble_);
31706
+ }
31707
+ if (this.bubbleShadow_ && this.bubbleShadow_.parentNode) {
31708
+ this.bubbleShadow_.parentNode.removeChild(this.bubbleShadow_);
31709
+ }
31710
+
31711
+ for (var i = 0, listener; listener = this.listeners_[i]; i++) {
31712
+ google.maps.event.removeListener(listener);
31713
+ }
31714
+ };
31715
+ InfoBubble.prototype['onRemove'] = InfoBubble.prototype.onRemove;
31716
+
31717
+
31718
+ /**
31719
+ * Is the InfoBubble open
31720
+ *
31721
+ * @return {boolean} If the InfoBubble is open.
31722
+ */
31723
+ InfoBubble.prototype.isOpen = function() {
31724
+ return this.isOpen_;
31725
+ };
31726
+ InfoBubble.prototype['isOpen'] = InfoBubble.prototype.isOpen;
31727
+
31728
+
31729
+ /**
31730
+ * Close the InfoBubble
31731
+ */
31732
+ InfoBubble.prototype.close = function() {
31733
+ if (this.bubble_) {
31734
+ this.bubble_.style['display'] = 'none';
31735
+ // Remove the animation so we next time it opens it will animate again
31736
+ this.bubble_.className =
31737
+ this.bubble_.className.replace(this.animationName_, '');
31738
+ }
31739
+
31740
+ if (this.bubbleShadow_) {
31741
+ this.bubbleShadow_.style['display'] = 'none';
31742
+ this.bubbleShadow_.className =
31743
+ this.bubbleShadow_.className.replace(this.animationName_, '');
31744
+ }
31745
+ this.isOpen_ = false;
31746
+ };
31747
+ InfoBubble.prototype['close'] = InfoBubble.prototype.close;
31748
+
31749
+
31750
+ /**
31751
+ * Open the InfoBubble (asynchronous).
31752
+ *
31753
+ * @param {google.maps.Map=} opt_map Optional map to open on.
31754
+ * @param {google.maps.MVCObject=} opt_anchor Optional anchor to position at.
31755
+ */
31756
+ InfoBubble.prototype.open = function(opt_map, opt_anchor) {
31757
+ var that = this;
31758
+ window.setTimeout(function() {
31759
+ that.open_(opt_map, opt_anchor);
31760
+ }, 0);
31761
+ };
31762
+
31763
+
31764
+ /**
31765
+ * Open the InfoBubble
31766
+ * @private
31767
+ * @param {google.maps.Map=} opt_map Optional map to open on.
31768
+ * @param {google.maps.MVCObject=} opt_anchor Optional anchor to position at.
31769
+ */
31770
+ InfoBubble.prototype.open_ = function(opt_map, opt_anchor) {
31771
+ this.updateContent_();
31772
+
31773
+ if (opt_map) {
31774
+ this.setMap(opt_map);
31775
+ }
31776
+
31777
+ if (opt_anchor) {
31778
+ this.set('anchor', opt_anchor);
31779
+ this.bindTo('anchorPoint', opt_anchor);
31780
+ this.bindTo('position', opt_anchor);
31781
+ }
31782
+
31783
+ // Show the bubble and the show
31784
+ this.bubble_.style['display'] = this.bubbleShadow_.style['display'] = '';
31785
+ var animation = !this.get('disableAnimation');
31786
+
31787
+ if (animation) {
31788
+ // Add the animation
31789
+ this.bubble_.className += ' ' + this.animationName_;
31790
+ this.bubbleShadow_.className += ' ' + this.animationName_;
31791
+ }
31792
+
31793
+ this.redraw_();
31794
+ this.isOpen_ = true;
31795
+
31796
+ var pan = !this.get('disableAutoPan');
31797
+ if (pan) {
31798
+ var that = this;
31799
+ window.setTimeout(function() {
31800
+ // Pan into view, done in a time out to make it feel nicer :)
31801
+ that.panToView();
31802
+ }, 200);
31803
+ }
31804
+ };
31805
+ InfoBubble.prototype['open'] = InfoBubble.prototype.open;
31806
+
31807
+
31808
+ /**
31809
+ * Set the position of the InfoBubble
31810
+ *
31811
+ * @param {google.maps.LatLng} position The position to set.
31812
+ */
31813
+ InfoBubble.prototype.setPosition = function(position) {
31814
+ if (position) {
31815
+ this.set('position', position);
31816
+ }
31817
+ };
31818
+ InfoBubble.prototype['setPosition'] = InfoBubble.prototype.setPosition;
31819
+
31820
+
31821
+ /**
31822
+ * Returns the position of the InfoBubble
31823
+ *
31824
+ * @return {google.maps.LatLng} the position.
31825
+ */
31826
+ InfoBubble.prototype.getPosition = function() {
31827
+ return /** @type {google.maps.LatLng} */ (this.get('position'));
31828
+ };
31829
+ InfoBubble.prototype['getPosition'] = InfoBubble.prototype.getPosition;
31830
+
31831
+
31832
+ /**
31833
+ * position changed MVC callback
31834
+ */
31835
+ InfoBubble.prototype.position_changed = function() {
31836
+ this.draw();
31837
+ };
31838
+ InfoBubble.prototype['position_changed'] = InfoBubble.prototype.position_changed;
31839
+
31840
+
31841
+ /**
31842
+ * Pan the InfoBubble into view
31843
+ */
31844
+ InfoBubble.prototype.panToView = function() {
31845
+ var projection = this.getProjection();
31846
+
31847
+ if (!projection) {
31848
+ // The map projection is not ready yet so do nothing
31849
+ return;
31850
+ }
31851
+
31852
+ if (!this.bubble_) {
31853
+ // No Bubble yet so do nothing
31854
+ return;
31855
+ }
31856
+
31857
+ var anchorHeight = this.getAnchorHeight_();
31858
+ var height = this.bubble_.offsetHeight + anchorHeight;
31859
+ var map = this.get('map');
31860
+ var mapDiv = map.getDiv();
31861
+ var mapHeight = mapDiv.offsetHeight;
31862
+
31863
+ var latLng = this.getPosition();
31864
+ var centerPos = projection.fromLatLngToContainerPixel(map.getCenter());
31865
+ var pos = projection.fromLatLngToContainerPixel(latLng);
31866
+
31867
+ // Find out how much space at the top is free
31868
+ var spaceTop = centerPos.y - height;
31869
+
31870
+ // Fine out how much space at the bottom is free
31871
+ var spaceBottom = mapHeight - centerPos.y;
31872
+
31873
+ var needsTop = spaceTop < 0;
31874
+ var deltaY = 0;
31875
+
31876
+ if (needsTop) {
31877
+ spaceTop *= -1;
31878
+ deltaY = (spaceTop + spaceBottom) / 2;
31879
+ }
31880
+
31881
+ pos.y -= deltaY;
31882
+ latLng = projection.fromContainerPixelToLatLng(pos);
31883
+
31884
+ if (map.getCenter() != latLng) {
31885
+ map.panTo(latLng);
31886
+ }
31887
+ };
31888
+ InfoBubble.prototype['panToView'] = InfoBubble.prototype.panToView;
31889
+
31890
+
31891
+ /**
31892
+ * Converts a HTML string to a document fragment.
31893
+ *
31894
+ * @param {string} htmlString The HTML string to convert.
31895
+ * @return {Node} A HTML document fragment.
31896
+ * @private
31897
+ */
31898
+ InfoBubble.prototype.htmlToDocumentFragment_ = function(htmlString) {
31899
+ htmlString = htmlString.replace(/^\s*([\S\s]*)\b\s*$/, '$1');
31900
+ var tempDiv = document.createElement('DIV');
31901
+ tempDiv.innerHTML = htmlString;
31902
+ if (tempDiv.childNodes.length == 1) {
31903
+ return /** @type {!Node} */ (tempDiv.removeChild(tempDiv.firstChild));
31904
+ } else {
31905
+ var fragment = document.createDocumentFragment();
31906
+ while (tempDiv.firstChild) {
31907
+ fragment.appendChild(tempDiv.firstChild);
31908
+ }
31909
+ return fragment;
31910
+ }
31911
+ };
31912
+
31913
+
31914
+ /**
31915
+ * Removes all children from the node.
31916
+ *
31917
+ * @param {Node} node The node to remove all children from.
31918
+ * @private
31919
+ */
31920
+ InfoBubble.prototype.removeChildren_ = function(node) {
31921
+ if (!node) {
31922
+ return;
31923
+ }
31924
+
31925
+ var child;
31926
+ while (child = node.firstChild) {
31927
+ node.removeChild(child);
31928
+ }
31929
+ };
31930
+
31931
+
31932
+ /**
31933
+ * Sets the content of the infobubble.
31934
+ *
31935
+ * @param {string|Node} content The content to set.
31936
+ */
31937
+ InfoBubble.prototype.setContent = function(content) {
31938
+ this.set('content', content);
31939
+ };
31940
+ InfoBubble.prototype['setContent'] = InfoBubble.prototype.setContent;
31941
+
31942
+
31943
+ /**
31944
+ * Get the content of the infobubble.
31945
+ *
31946
+ * @return {string|Node} The marker content.
31947
+ */
31948
+ InfoBubble.prototype.getContent = function() {
31949
+ return /** @type {Node|string} */ (this.get('content'));
31950
+ };
31951
+ InfoBubble.prototype['getContent'] = InfoBubble.prototype.getContent;
31952
+
31953
+
31954
+ /**
31955
+ * Sets the marker content and adds loading events to images
31956
+ */
31957
+ InfoBubble.prototype.updateContent_ = function() {
31958
+ if (!this.content_) {
31959
+ // The Content area doesnt exist.
31960
+ return;
31961
+ }
31962
+
31963
+ this.removeChildren_(this.content_);
31964
+ var content = this.getContent();
31965
+ if (content) {
31966
+ if (typeof content == 'string') {
31967
+ content = this.htmlToDocumentFragment_(content);
31968
+ }
31969
+ this.content_.appendChild(content);
31970
+
31971
+ var that = this;
31972
+ var images = this.content_.getElementsByTagName('IMG');
31973
+ for (var i = 0, image; image = images[i]; i++) {
31974
+ // Because we don't know the size of an image till it loads, add a
31975
+ // listener to the image load so the marker can resize and reposition
31976
+ // itself to be the correct height.
31977
+ google.maps.event.addDomListener(image, 'load', function() {
31978
+ that.imageLoaded_();
31979
+ });
31980
+ }
31981
+ }
31982
+ this.redraw_();
31983
+ };
31984
+
31985
+
31986
+ /**
31987
+ * Image loaded
31988
+ * @private
31989
+ */
31990
+ InfoBubble.prototype.imageLoaded_ = function() {
31991
+ var pan = !this.get('disableAutoPan');
31992
+ this.redraw_();
31993
+ if (pan && (this.tabs_.length == 0 || this.activeTab_.index == 0)) {
31994
+ this.panToView();
31995
+ }
31996
+ };
31997
+
31998
+
31999
+ /**
32000
+ * Updates the styles of the tabs
32001
+ * @private
32002
+ */
32003
+ InfoBubble.prototype.updateTabStyles_ = function() {
32004
+ if (this.tabs_ && this.tabs_.length) {
32005
+ for (var i = 0, tab; tab = this.tabs_[i]; i++) {
32006
+ this.setTabStyle_(tab.tab);
32007
+ }
32008
+ this.activeTab_.style['zIndex'] = this.baseZIndex_;
32009
+ var borderWidth = this.getBorderWidth_();
32010
+ var padding = this.getPadding_() / 2;
32011
+ this.activeTab_.style['borderBottomWidth'] = 0;
32012
+ this.activeTab_.style['paddingBottom'] = this.px(padding + borderWidth);
32013
+ }
32014
+ };
32015
+
32016
+
32017
+ /**
32018
+ * Sets the style of a tab
32019
+ * @private
32020
+ * @param {Element} tab The tab to style.
32021
+ */
32022
+ InfoBubble.prototype.setTabStyle_ = function(tab) {
32023
+ var backgroundColor = this.get('backgroundColor');
32024
+ var borderColor = this.get('borderColor');
32025
+ var borderRadius = this.getBorderRadius_();
32026
+ var borderWidth = this.getBorderWidth_();
32027
+ var padding = this.getPadding_();
32028
+
32029
+ var marginRight = this.px(-(Math.max(padding, borderRadius)));
32030
+ var borderRadiusPx = this.px(borderRadius);
32031
+
32032
+ var index = this.baseZIndex_;
32033
+ if (tab.index) {
32034
+ index -= tab.index;
32035
+ }
32036
+
32037
+ // The styles for the tab
32038
+ var styles = {
32039
+ 'cssFloat': 'left',
32040
+ 'position': 'relative',
32041
+ 'cursor': 'pointer',
32042
+ 'backgroundColor': backgroundColor,
32043
+ 'border': this.px(borderWidth) + ' solid ' + borderColor,
32044
+ 'padding': this.px(padding / 2) + ' ' + this.px(padding),
32045
+ 'marginRight': marginRight,
32046
+ 'whiteSpace': 'nowrap',
32047
+ 'borderRadiusTopLeft': borderRadiusPx,
32048
+ 'MozBorderRadiusTopleft': borderRadiusPx,
32049
+ 'webkitBorderTopLeftRadius': borderRadiusPx,
32050
+ 'borderRadiusTopRight': borderRadiusPx,
32051
+ 'MozBorderRadiusTopright': borderRadiusPx,
32052
+ 'webkitBorderTopRightRadius': borderRadiusPx,
32053
+ 'zIndex': index,
32054
+ 'display': 'inline'
32055
+ };
32056
+
32057
+ for (var style in styles) {
32058
+ tab.style[style] = styles[style];
32059
+ }
32060
+
32061
+ var className = this.get('tabClassName');
32062
+ if (className != undefined) {
32063
+ tab.className += ' ' + className;
32064
+ }
32065
+ };
32066
+
32067
+
32068
+ /**
32069
+ * Add user actions to a tab
32070
+ * @private
32071
+ * @param {Object} tab The tab to add the actions to.
32072
+ */
32073
+ InfoBubble.prototype.addTabActions_ = function(tab) {
32074
+ var that = this;
32075
+ tab.listener_ = google.maps.event.addDomListener(tab, 'click', function() {
32076
+ that.setTabActive_(this);
32077
+ });
32078
+ };
32079
+
32080
+
32081
+ /**
32082
+ * Set a tab at a index to be active
32083
+ *
32084
+ * @param {number} index The index of the tab.
32085
+ */
32086
+ InfoBubble.prototype.setTabActive = function(index) {
32087
+ var tab = this.tabs_[index - 1];
32088
+
32089
+ if (tab) {
32090
+ this.setTabActive_(tab.tab);
32091
+ }
32092
+ };
32093
+ InfoBubble.prototype['setTabActive'] = InfoBubble.prototype.setTabActive;
32094
+
32095
+
32096
+ /**
32097
+ * Set a tab to be active
32098
+ * @private
32099
+ * @param {Object} tab The tab to set active.
32100
+ */
32101
+ InfoBubble.prototype.setTabActive_ = function(tab) {
32102
+ if (!tab) {
32103
+ this.setContent('');
32104
+ this.updateContent_();
32105
+ return;
32106
+ }
32107
+
32108
+ var padding = this.getPadding_() / 2;
32109
+ var borderWidth = this.getBorderWidth_();
32110
+
32111
+ if (this.activeTab_) {
32112
+ var activeTab = this.activeTab_;
32113
+ activeTab.style['zIndex'] = this.baseZIndex_ - activeTab.index;
32114
+ activeTab.style['paddingBottom'] = this.px(padding);
32115
+ activeTab.style['borderBottomWidth'] = this.px(borderWidth);
32116
+ }
32117
+
32118
+ tab.style['zIndex'] = this.baseZIndex_;
32119
+ tab.style['borderBottomWidth'] = 0;
32120
+ tab.style['marginBottomWidth'] = '-10px';
32121
+ tab.style['paddingBottom'] = this.px(padding + borderWidth);
32122
+
32123
+ this.setContent(this.tabs_[tab.index].content);
32124
+ this.updateContent_();
32125
+
32126
+ this.activeTab_ = tab;
32127
+
32128
+ this.redraw_();
32129
+ };
32130
+
32131
+
32132
+ /**
32133
+ * Set the max width of the InfoBubble
32134
+ *
32135
+ * @param {number} width The max width.
32136
+ */
32137
+ InfoBubble.prototype.setMaxWidth = function(width) {
32138
+ this.set('maxWidth', width);
32139
+ };
32140
+ InfoBubble.prototype['setMaxWidth'] = InfoBubble.prototype.setMaxWidth;
32141
+
32142
+
32143
+ /**
32144
+ * maxWidth changed MVC callback
32145
+ */
32146
+ InfoBubble.prototype.maxWidth_changed = function() {
32147
+ this.redraw_();
32148
+ };
32149
+ InfoBubble.prototype['maxWidth_changed'] = InfoBubble.prototype.maxWidth_changed;
32150
+
32151
+
32152
+ /**
32153
+ * Set the max height of the InfoBubble
32154
+ *
32155
+ * @param {number} height The max height.
32156
+ */
32157
+ InfoBubble.prototype.setMaxHeight = function(height) {
32158
+ this.set('maxHeight', height);
32159
+ };
32160
+ InfoBubble.prototype['setMaxHeight'] = InfoBubble.prototype.setMaxHeight;
32161
+
32162
+
32163
+ /**
32164
+ * maxHeight changed MVC callback
32165
+ */
32166
+ InfoBubble.prototype.maxHeight_changed = function() {
32167
+ this.redraw_();
32168
+ };
32169
+ InfoBubble.prototype['maxHeight_changed'] = InfoBubble.prototype.maxHeight_changed;
32170
+
32171
+
32172
+ /**
32173
+ * Set the min width of the InfoBubble
32174
+ *
32175
+ * @param {number} width The min width.
32176
+ */
32177
+ InfoBubble.prototype.setMinWidth = function(width) {
32178
+ this.set('minWidth', width);
32179
+ };
32180
+ InfoBubble.prototype['setMinWidth'] = InfoBubble.prototype.setMinWidth;
32181
+
32182
+
32183
+ /**
32184
+ * minWidth changed MVC callback
32185
+ */
32186
+ InfoBubble.prototype.minWidth_changed = function() {
32187
+ this.redraw_();
32188
+ };
32189
+ InfoBubble.prototype['minWidth_changed'] = InfoBubble.prototype.minWidth_changed;
32190
+
32191
+
32192
+ /**
32193
+ * Set the min height of the InfoBubble
32194
+ *
32195
+ * @param {number} height The min height.
32196
+ */
32197
+ InfoBubble.prototype.setMinHeight = function(height) {
32198
+ this.set('minHeight', height);
32199
+ };
32200
+ InfoBubble.prototype['setMinHeight'] = InfoBubble.prototype.setMinHeight;
32201
+
32202
+
32203
+ /**
32204
+ * minHeight changed MVC callback
32205
+ */
32206
+ InfoBubble.prototype.minHeight_changed = function() {
32207
+ this.redraw_();
32208
+ };
32209
+ InfoBubble.prototype['minHeight_changed'] = InfoBubble.prototype.minHeight_changed;
32210
+
32211
+
32212
+ /**
32213
+ * Add a tab
32214
+ *
32215
+ * @param {string} label The label of the tab.
32216
+ * @param {string|Element} content The content of the tab.
32217
+ */
32218
+ InfoBubble.prototype.addTab = function(label, content) {
32219
+ var tab = document.createElement('DIV');
32220
+ tab.innerHTML = label;
32221
+
32222
+ this.setTabStyle_(tab);
32223
+ this.addTabActions_(tab);
32224
+
32225
+ this.tabsContainer_.appendChild(tab);
32226
+
32227
+ this.tabs_.push({
32228
+ label: label,
32229
+ content: content,
32230
+ tab: tab
32231
+ });
32232
+
32233
+ tab.index = this.tabs_.length - 1;
32234
+ tab.style['zIndex'] = this.baseZIndex_ - tab.index;
32235
+
32236
+ if (!this.activeTab_) {
32237
+ this.setTabActive_(tab);
32238
+ }
32239
+
32240
+ tab.className = tab.className + ' ' + this.animationName_;
32241
+
32242
+ this.redraw_();
32243
+ };
32244
+ InfoBubble.prototype['addTab'] = InfoBubble.prototype.addTab;
32245
+
32246
+
32247
+ /**
32248
+ * Update a tab at a speicifc index
32249
+ *
32250
+ * @param {number} index The index of the tab.
32251
+ * @param {?string} opt_label The label to change to.
32252
+ * @param {?string} opt_content The content to update to.
32253
+ */
32254
+ InfoBubble.prototype.updateTab = function(index, opt_label, opt_content) {
32255
+ if (!this.tabs_.length || index < 0 || index >= this.tabs_.length) {
32256
+ return;
32257
+ }
32258
+
32259
+ var tab = this.tabs_[index];
32260
+ if (opt_label != undefined) {
32261
+ tab.tab.innerHTML = tab.label = opt_label;
32262
+ }
32263
+
32264
+ if (opt_content != undefined) {
32265
+ tab.content = opt_content;
32266
+ }
32267
+
32268
+ if (this.activeTab_ == tab.tab) {
32269
+ this.setContent(tab.content);
32270
+ this.updateContent_();
32271
+ }
32272
+ this.redraw_();
32273
+ };
32274
+ InfoBubble.prototype['updateTab'] = InfoBubble.prototype.updateTab;
32275
+
32276
+
32277
+ /**
32278
+ * Remove a tab at a specific index
32279
+ *
32280
+ * @param {number} index The index of the tab to remove.
32281
+ */
32282
+ InfoBubble.prototype.removeTab = function(index) {
32283
+ if (!this.tabs_.length || index < 0 || index >= this.tabs_.length) {
32284
+ return;
32285
+ }
32286
+
32287
+ var tab = this.tabs_[index];
32288
+ tab.tab.parentNode.removeChild(tab.tab);
32289
+
32290
+ google.maps.event.removeListener(tab.tab.listener_);
32291
+
32292
+ this.tabs_.splice(index, 1);
32293
+
32294
+ delete tab;
32295
+
32296
+ for (var i = 0, t; t = this.tabs_[i]; i++) {
32297
+ t.tab.index = i;
32298
+ }
32299
+
32300
+ if (tab.tab == this.activeTab_) {
32301
+ // Removing the current active tab
32302
+ if (this.tabs_[index]) {
32303
+ // Show the tab to the right
32304
+ this.activeTab_ = this.tabs_[index].tab;
32305
+ } else if (this.tabs_[index - 1]) {
32306
+ // Show a tab to the left
32307
+ this.activeTab_ = this.tabs_[index - 1].tab;
32308
+ } else {
32309
+ // No tabs left to sho
32310
+ this.activeTab_ = undefined;
32311
+ }
32312
+
32313
+ this.setTabActive_(this.activeTab_);
32314
+ }
32315
+
32316
+ this.redraw_();
32317
+ };
32318
+ InfoBubble.prototype['removeTab'] = InfoBubble.prototype.removeTab;
32319
+
32320
+
32321
+ /**
32322
+ * Get the size of an element
32323
+ * @private
32324
+ * @param {Node|string} element The element to size.
32325
+ * @param {number=} opt_maxWidth Optional max width of the element.
32326
+ * @param {number=} opt_maxHeight Optional max height of the element.
32327
+ * @return {google.maps.Size} The size of the element.
32328
+ */
32329
+ InfoBubble.prototype.getElementSize_ = function(element, opt_maxWidth,
32330
+ opt_maxHeight) {
32331
+ var sizer = document.createElement('DIV');
32332
+ sizer.style['display'] = 'inline';
32333
+ sizer.style['position'] = 'absolute';
32334
+ sizer.style['visibility'] = 'hidden';
32335
+
32336
+ if (typeof element == 'string') {
32337
+ sizer.innerHTML = element;
32338
+ } else {
32339
+ sizer.appendChild(element.cloneNode(true));
32340
+ }
32341
+
32342
+ document.body.appendChild(sizer);
32343
+ var size = new google.maps.Size(sizer.offsetWidth, sizer.offsetHeight);
32344
+
32345
+ // If the width is bigger than the max width then set the width and size again
32346
+ if (opt_maxWidth && size.width > opt_maxWidth) {
32347
+ sizer.style['width'] = this.px(opt_maxWidth);
32348
+ size = new google.maps.Size(sizer.offsetWidth, sizer.offsetHeight);
32349
+ }
32350
+
32351
+ // If the height is bigger than the max height then set the height and size
32352
+ // again
32353
+ if (opt_maxHeight && size.height > opt_maxHeight) {
32354
+ sizer.style['height'] = this.px(opt_maxHeight);
32355
+ size = new google.maps.Size(sizer.offsetWidth, sizer.offsetHeight);
32356
+ }
32357
+
32358
+ document.body.removeChild(sizer);
32359
+ delete sizer;
32360
+ return size;
32361
+ };
32362
+
32363
+
32364
+ /**
32365
+ * Redraw the InfoBubble
32366
+ * @private
32367
+ */
32368
+ InfoBubble.prototype.redraw_ = function() {
32369
+ this.figureOutSize_();
32370
+ this.positionCloseButton_();
32371
+ this.draw();
32372
+ };
32373
+
32374
+
32375
+ /**
32376
+ * Figure out the optimum size of the InfoBubble
32377
+ * @private
32378
+ */
32379
+ InfoBubble.prototype.figureOutSize_ = function() {
32380
+ var map = this.get('map');
32381
+
32382
+ if (!map) {
32383
+ return;
32384
+ }
32385
+
32386
+ var padding = this.getPadding_();
32387
+ var borderWidth = this.getBorderWidth_();
32388
+ var borderRadius = this.getBorderRadius_();
32389
+ var arrowSize = this.getArrowSize_();
32390
+
32391
+ var mapDiv = map.getDiv();
32392
+ var gutter = arrowSize * 2;
32393
+ var mapWidth = mapDiv.offsetWidth - gutter;
32394
+ var mapHeight = mapDiv.offsetHeight - gutter - this.getAnchorHeight_();
32395
+ var tabHeight = 0;
32396
+ var width = /** @type {number} */ (this.get('minWidth') || 0);
32397
+ var height = /** @type {number} */ (this.get('minHeight') || 0);
32398
+ var maxWidth = /** @type {number} */ (this.get('maxWidth') || 0);
32399
+ var maxHeight = /** @type {number} */ (this.get('maxHeight') || 0);
32400
+
32401
+ maxWidth = Math.min(mapWidth, maxWidth);
32402
+ maxHeight = Math.min(mapHeight, maxHeight);
32403
+
32404
+ var tabWidth = 0;
32405
+ if (this.tabs_.length) {
32406
+ // If there are tabs then you need to check the size of each tab's content
32407
+ for (var i = 0, tab; tab = this.tabs_[i]; i++) {
32408
+ var tabSize = this.getElementSize_(tab.tab, maxWidth, maxHeight);
32409
+ var contentSize = this.getElementSize_(tab.content, maxWidth, maxHeight);
32410
+
32411
+ if (width < tabSize.width) {
32412
+ width = tabSize.width;
32413
+ }
32414
+
32415
+ // Add up all the tab widths because they might end up being wider than
32416
+ // the content
32417
+ tabWidth += tabSize.width;
32418
+
32419
+ if (height < tabSize.height) {
32420
+ height = tabSize.height;
32421
+ }
32422
+
32423
+ if (tabSize.height > tabHeight) {
32424
+ tabHeight = tabSize.height;
32425
+ }
32426
+
32427
+ if (width < contentSize.width) {
32428
+ width = contentSize.width;
32429
+ }
32430
+
32431
+ if (height < contentSize.height) {
32432
+ height = contentSize.height;
32433
+ }
32434
+ }
32435
+ } else {
32436
+ var content = /** @type {string|Node} */ (this.get('content'));
32437
+ if (typeof content == 'string') {
32438
+ content = this.htmlToDocumentFragment_(content);
32439
+ }
32440
+ if (content) {
32441
+ var contentSize = this.getElementSize_(content, maxWidth, maxHeight);
32442
+
32443
+ if (width < contentSize.width) {
32444
+ width = contentSize.width;
32445
+ }
32446
+
32447
+ if (height < contentSize.height) {
32448
+ height = contentSize.height;
32449
+ }
32450
+ }
32451
+ }
32452
+
32453
+ if (maxWidth) {
32454
+ width = Math.min(width, maxWidth);
32455
+ }
32456
+
32457
+ if (maxHeight) {
32458
+ height = Math.min(height, maxHeight);
32459
+ }
32460
+
32461
+ width = Math.max(width, tabWidth);
32462
+
32463
+ if (width == tabWidth) {
32464
+ width = width + 2 * padding;
32465
+ }
32466
+
32467
+ arrowSize = arrowSize * 2;
32468
+ width = Math.max(width, arrowSize);
32469
+
32470
+ // Maybe add this as a option so they can go bigger than the map if the user
32471
+ // wants
32472
+ if (width > mapWidth) {
32473
+ width = mapWidth;
32474
+ }
32475
+
32476
+ if (height > mapHeight) {
32477
+ height = mapHeight - tabHeight;
32478
+ }
32479
+
32480
+ if (this.tabsContainer_) {
32481
+ this.tabHeight_ = tabHeight;
32482
+ this.tabsContainer_.style['width'] = this.px(tabWidth);
32483
+ }
32484
+
32485
+ this.contentContainer_.style['width'] = this.px(width);
32486
+ this.contentContainer_.style['height'] = this.px(height);
32487
+ };
32488
+
32489
+
32490
+ /**
32491
+ * Get the height of the anchor
32492
+ *
32493
+ * This function is a hack for now and doesn't really work that good, need to
32494
+ * wait for pixelBounds to be correctly exposed.
32495
+ * @private
32496
+ * @return {number} The height of the anchor.
32497
+ */
32498
+ InfoBubble.prototype.getAnchorHeight_ = function() {
32499
+ var anchor = this.get('anchor');
32500
+ if (anchor) {
32501
+ var anchorPoint = /** @type google.maps.Point */(this.get('anchorPoint'));
32502
+
32503
+ if (anchorPoint) {
32504
+ return -1 * anchorPoint.y;
32505
+ }
32506
+ }
32507
+ return 0;
32508
+ };
32509
+
32510
+ InfoBubble.prototype.anchorPoint_changed = function() {
32511
+ this.draw();
32512
+ };
32513
+ InfoBubble.prototype['anchorPoint_changed'] = InfoBubble.prototype.anchorPoint_changed;
32514
+
32515
+
32516
+ /**
32517
+ * Position the close button in the right spot.
32518
+ * @private
32519
+ */
32520
+ InfoBubble.prototype.positionCloseButton_ = function() {
32521
+ var br = this.getBorderRadius_();
32522
+ var bw = this.getBorderWidth_();
32523
+
32524
+ var right = 2;
32525
+ var top = 2;
32526
+
32527
+ if (this.tabs_.length && this.tabHeight_) {
32528
+ top += this.tabHeight_;
32529
+ }
32530
+
32531
+ top += bw;
32532
+ right += bw;
32533
+
32534
+ var c = this.contentContainer_;
32535
+ if (c && c.clientHeight < c.scrollHeight) {
32536
+ // If there are scrollbars then move the cross in so it is not over
32537
+ // scrollbar
32538
+ right += 15;
32539
+ }
32540
+
32541
+ this.close_.style['right'] = this.px(right);
32542
+ this.close_.style['top'] = this.px(top);
32543
+ };
32544
+
32545
+
30633
32546
  /***/ }
30634
32547
  /******/ ]);