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

Sign up to get free protection for your applications and to get access to all the features.
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
  /******/ ]);