Guest User

Untitled

a guest
May 12th, 2016
790
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /**
  2.  * @name InfoBox
  3.  * @version 1.1.13 [March 19, 2014]
  4.  * @author Gary Little (inspired by proof-of-concept code from Pamela Fox of Google)
  5.  * @copyright Copyright 2010 Gary Little [gary at luxcentral.com]
  6.  * @fileoverview InfoBox extends the Google Maps JavaScript API V3 <tt>OverlayView</tt> class.
  7.  *  <p>
  8.  *  An InfoBox behaves like a <tt>google.maps.InfoWindow</tt>, but it supports several
  9.  *  additional properties for advanced styling. An InfoBox can also be used as a map label.
  10.  *  <p>
  11.  *  An InfoBox also fires the same events as a <tt>google.maps.InfoWindow</tt>.
  12.  */
  13.  
  14. /*!
  15.  *
  16.  * Licensed under the Apache License, Version 2.0 (the "License");
  17.  * you may not use this file except in compliance with the License.
  18.  * You may obtain a copy of the License at
  19.  *
  20.  *       http://www.apache.org/licenses/LICENSE-2.0
  21.  *
  22.  * Unless required by applicable law or agreed to in writing, software
  23.  * distributed under the License is distributed on an "AS IS" BASIS,
  24.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  25.  * See the License for the specific language governing permissions and
  26.  * limitations under the License.
  27.  */
  28.  
  29. /*jslint browser:true */
  30. /*global google */
  31.  
  32. /**
  33.  * @name InfoBoxOptions
  34.  * @class This class represents the optional parameter passed to the {@link InfoBox} constructor.
  35.  * @property {string|Node} content The content of the InfoBox (plain text or an HTML DOM node).
  36.  * @property {boolean} [disableAutoPan=false] Disable auto-pan on <tt>open</tt>.
  37.  * @property {number} maxWidth The maximum width (in pixels) of the InfoBox. Set to 0 if no maximum.
  38.  * @property {Size} pixelOffset The offset (in pixels) from the top left corner of the InfoBox
  39.  *  (or the bottom left corner if the <code>alignBottom</code> property is <code>true</code>)
  40.  *  to the map pixel corresponding to <tt>position</tt>.
  41.  * @property {LatLng} position The geographic location at which to display the InfoBox.
  42.  * @property {number} zIndex The CSS z-index style value for the InfoBox.
  43.  *  Note: This value overrides a zIndex setting specified in the <tt>boxStyle</tt> property.
  44.  * @property {string} [boxClass="infoBox"] The name of the CSS class defining the styles for the InfoBox container.
  45.  * @property {Object} [boxStyle] An object literal whose properties define specific CSS
  46.  *  style values to be applied to the InfoBox. Style values defined here override those that may
  47.  *  be defined in the <code>boxClass</code> style sheet. If this property is changed after the
  48.  *  InfoBox has been created, all previously set styles (except those defined in the style sheet)
  49.  *  are removed from the InfoBox before the new style values are applied.
  50.  * @property {string} closeBoxMargin The CSS margin style value for the close box.
  51.  *  The default is "2px" (a 2-pixel margin on all sides).
  52.  * @property {string} closeBoxURL The URL of the image representing the close box.
  53.  *  Note: The default is the URL for Google's standard close box.
  54.  *  Set this property to "" if no close box is required.
  55.  * @property {Size} infoBoxClearance Minimum offset (in pixels) from the InfoBox to the
  56.  *  map edge after an auto-pan.
  57.  * @property {boolean} [isHidden=false] Hide the InfoBox on <tt>open</tt>.
  58.  *  [Deprecated in favor of the <tt>visible</tt> property.]
  59.  * @property {boolean} [visible=true] Show the InfoBox on <tt>open</tt>.
  60.  * @property {boolean} alignBottom Align the bottom left corner of the InfoBox to the <code>position</code>
  61.  *  location (default is <tt>false</tt> which means that the top left corner of the InfoBox is aligned).
  62.  * @property {string} pane The pane where the InfoBox is to appear (default is "floatPane").
  63.  *  Set the pane to "mapPane" if the InfoBox is being used as a map label.
  64.  *  Valid pane names are the property names for the <tt>google.maps.MapPanes</tt> object.
  65.  * @property {boolean} enableEventPropagation Propagate mousedown, mousemove, mouseover, mouseout,
  66.  *  mouseup, click, dblclick, touchstart, touchend, touchmove, and contextmenu events in the InfoBox
  67.  *  (default is <tt>false</tt> to mimic the behavior of a <tt>google.maps.InfoWindow</tt>). Set
  68.  *  this property to <tt>true</tt> if the InfoBox is being used as a map label.
  69.  */
  70.  
  71. /**
  72.  * Creates an InfoBox with the options specified in {@link InfoBoxOptions}.
  73.  *  Call <tt>InfoBox.open</tt> to add the box to the map.
  74.  * @constructor
  75.  * @param {InfoBoxOptions} [opt_opts]
  76.  */
  77. function InfoBox(opt_opts) {
  78.  
  79.   opt_opts = opt_opts || {};
  80.  
  81.   google.maps.OverlayView.apply(this, arguments);
  82.  
  83.   // Standard options (in common with google.maps.InfoWindow):
  84.   //
  85.   this.content_ = opt_opts.content || "";
  86.   this.disableAutoPan_ = opt_opts.disableAutoPan || false;
  87.   this.maxWidth_ = opt_opts.maxWidth || 0;
  88.   this.pixelOffset_ = opt_opts.pixelOffset || new google.maps.Size(0, 0);
  89.   this.position_ = opt_opts.position || new google.maps.LatLng(0, 0);
  90.   this.zIndex_ = opt_opts.zIndex || null;
  91.  
  92.   // Additional options (unique to InfoBox):
  93.   //
  94.   this.boxClass_ = opt_opts.boxClass || "infoBox";
  95.   this.boxStyle_ = opt_opts.boxStyle || {};
  96.   this.closeBoxMargin_ = opt_opts.closeBoxMargin || "2px";
  97.   this.closeBoxURL_ = opt_opts.closeBoxURL || "http://www.google.com/intl/en_us/mapfiles/close.gif";
  98.   if (opt_opts.closeBoxURL === "") {
  99.     this.closeBoxURL_ = "";
  100.   }
  101.   this.infoBoxClearance_ = opt_opts.infoBoxClearance || new google.maps.Size(1, 1);
  102.  
  103.   if (typeof opt_opts.visible === "undefined") {
  104.     if (typeof opt_opts.isHidden === "undefined") {
  105.       opt_opts.visible = true;
  106.     } else {
  107.       opt_opts.visible = !opt_opts.isHidden;
  108.     }
  109.   }
  110.   this.isHidden_ = !opt_opts.visible;
  111.  
  112.   this.alignBottom_ = opt_opts.alignBottom || false;
  113.   this.pane_ = opt_opts.pane || "floatPane";
  114.   this.enableEventPropagation_ = opt_opts.enableEventPropagation || false;
  115.  
  116.   this.div_ = null;
  117.   this.closeListener_ = null;
  118.   this.moveListener_ = null;
  119.   this.contextListener_ = null;
  120.   this.eventListeners_ = null;
  121.   this.fixedWidthSet_ = null;
  122. }
  123.  
  124. /* InfoBox extends OverlayView in the Google Maps API v3.
  125.  */
  126. InfoBox.prototype = new google.maps.OverlayView();
  127.  
  128. /**
  129.  * Creates the DIV representing the InfoBox.
  130.  * @private
  131.  */
  132. InfoBox.prototype.createInfoBoxDiv_ = function () {
  133.  
  134.   var i;
  135.   var events;
  136.   var bw;
  137.   var me = this;
  138.  
  139.   // This handler prevents an event in the InfoBox from being passed on to the map.
  140.   //
  141.   var cancelHandler = function (e) {
  142.     e.cancelBubble = true;
  143.     if (e.stopPropagation) {
  144.       e.stopPropagation();
  145.     }
  146.   };
  147.  
  148.   // This handler ignores the current event in the InfoBox and conditionally prevents
  149.   // the event from being passed on to the map. It is used for the contextmenu event.
  150.   //
  151.   var ignoreHandler = function (e) {
  152.  
  153.     e.returnValue = false;
  154.  
  155.     if (e.preventDefault) {
  156.  
  157.       e.preventDefault();
  158.     }
  159.  
  160.     if (!me.enableEventPropagation_) {
  161.  
  162.       cancelHandler(e);
  163.     }
  164.   };
  165.  
  166.   if (!this.div_) {
  167.  
  168.     this.div_ = document.createElement("div");
  169.  
  170.     this.setBoxStyle_();
  171.  
  172.     if (typeof this.content_.nodeType === "undefined") {
  173.       this.div_.innerHTML = this.getCloseBoxImg_() + this.content_;
  174.     } else {
  175.       this.div_.innerHTML = this.getCloseBoxImg_();
  176.       this.div_.appendChild(this.content_);
  177.     }
  178.  
  179.     // Add the InfoBox DIV to the DOM
  180.     this.getPanes()[this.pane_].appendChild(this.div_);
  181.  
  182.     this.addClickHandler_();
  183.  
  184.     if (this.div_.style.width) {
  185.  
  186.       this.fixedWidthSet_ = true;
  187.  
  188.     } else {
  189.  
  190.       if (this.maxWidth_ !== 0 && this.div_.offsetWidth > this.maxWidth_) {
  191.  
  192.         this.div_.style.width = this.maxWidth_;
  193.         this.div_.style.overflow = "auto";
  194.         this.fixedWidthSet_ = true;
  195.  
  196.       } else { // The following code is needed to overcome problems with MSIE
  197.  
  198.         bw = this.getBoxWidths_();
  199.  
  200.         this.div_.style.width = (this.div_.offsetWidth - bw.left - bw.right) + "px";
  201.         this.fixedWidthSet_ = false;
  202.       }
  203.     }
  204.  
  205.     this.panBox_(this.disableAutoPan_);
  206.  
  207.     if (!this.enableEventPropagation_) {
  208.  
  209.       this.eventListeners_ = [];
  210.  
  211.       // Cancel event propagation.
  212.       //
  213.       // Note: mousemove not included (to resolve Issue 152)
  214.       events = ["mousedown", "mouseover", "mouseout", "mouseup",
  215.       "click", "dblclick", "touchstart", "touchend", "touchmove"];
  216.  
  217.       for (i = 0; i < events.length; i++) {
  218.  
  219.         this.eventListeners_.push(google.maps.event.addDomListener(this.div_, events[i], cancelHandler));
  220.       }
  221.      
  222.       // Workaround for Google bug that causes the cursor to change to a pointer
  223.       // when the mouse moves over a marker underneath InfoBox.
  224.       this.eventListeners_.push(google.maps.event.addDomListener(this.div_, "mouseover", function (e) {
  225.         this.style.cursor = "default";
  226.       }));
  227.     }
  228.  
  229.     this.contextListener_ = google.maps.event.addDomListener(this.div_, "contextmenu", ignoreHandler);
  230.  
  231.     /**
  232.      * This event is fired when the DIV containing the InfoBox's content is attached to the DOM.
  233.      * @name InfoBox#domready
  234.      * @event
  235.      */
  236.     google.maps.event.trigger(this, "domready");
  237.   }
  238. };
  239.  
  240. /**
  241.  * Returns the HTML <IMG> tag for the close box.
  242.  * @private
  243.  */
  244. InfoBox.prototype.getCloseBoxImg_ = function () {
  245.  
  246.   var img = "";
  247.  
  248.   if (this.closeBoxURL_ !== "") {
  249.  
  250.     img  = "<img";
  251.     img += " src='" + this.closeBoxURL_ + "'";
  252.     img += " align=right"; // Do this because Opera chokes on style='float: right;'
  253.     img += " style='";
  254.     img += " position: relative;"; // Required by MSIE
  255.     img += " cursor: pointer;";
  256.     img += " margin: " + this.closeBoxMargin_ + ";";
  257.     img += "'>";
  258.   }
  259.  
  260.   return img;
  261. };
  262.  
  263. /**
  264.  * Adds the click handler to the InfoBox close box.
  265.  * @private
  266.  */
  267. InfoBox.prototype.addClickHandler_ = function () {
  268.  
  269.   var closeBox;
  270.  
  271.   if (this.closeBoxURL_ !== "") {
  272.  
  273.     closeBox = this.div_.firstChild;
  274.     this.closeListener_ = google.maps.event.addDomListener(closeBox, "click", this.getCloseClickHandler_());
  275.  
  276.   } else {
  277.  
  278.     this.closeListener_ = null;
  279.   }
  280. };
  281.  
  282. /**
  283.  * Returns the function to call when the user clicks the close box of an InfoBox.
  284.  * @private
  285.  */
  286. InfoBox.prototype.getCloseClickHandler_ = function () {
  287.  
  288.   var me = this;
  289.  
  290.   return function (e) {
  291.  
  292.     // 1.0.3 fix: Always prevent propagation of a close box click to the map:
  293.     e.cancelBubble = true;
  294.  
  295.     if (e.stopPropagation) {
  296.  
  297.       e.stopPropagation();
  298.     }
  299.  
  300.     /**
  301.      * This event is fired when the InfoBox's close box is clicked.
  302.      * @name InfoBox#closeclick
  303.      * @event
  304.      */
  305.     google.maps.event.trigger(me, "closeclick");
  306.  
  307.     me.close();
  308.   };
  309. };
  310.  
  311. /**
  312.  * Pans the map so that the InfoBox appears entirely within the map's visible area.
  313.  * @private
  314.  */
  315. InfoBox.prototype.panBox_ = function (disablePan) {
  316.  
  317.   var map;
  318.   var bounds;
  319.   var xOffset = 0, yOffset = 0;
  320.  
  321.   if (!disablePan) {
  322.  
  323.     map = this.getMap();
  324.  
  325.     if (map instanceof google.maps.Map) { // Only pan if attached to map, not panorama
  326.  
  327.       if (!map.getBounds().contains(this.position_)) {
  328.       // Marker not in visible area of map, so set center
  329.       // of map to the marker position first.
  330.         map.setCenter(this.position_);
  331.       }
  332.  
  333.       bounds = map.getBounds();
  334.  
  335.       var mapDiv = map.getDiv();
  336.       var mapWidth = mapDiv.offsetWidth;
  337.       var mapHeight = mapDiv.offsetHeight;
  338.       var iwOffsetX = this.pixelOffset_.width;
  339.       var iwOffsetY = this.pixelOffset_.height;
  340.       var iwWidth = this.div_.offsetWidth;
  341.       var iwHeight = this.div_.offsetHeight;
  342.       var padX = this.infoBoxClearance_.width;
  343.       var padY = this.infoBoxClearance_.height;
  344.       var pixPosition = this.getProjection().fromLatLngToContainerPixel(this.position_);
  345.  
  346.       if (pixPosition.x < (-iwOffsetX + padX)) {
  347.         xOffset = pixPosition.x + iwOffsetX - padX;
  348.       } else if ((pixPosition.x + iwWidth + iwOffsetX + padX) > mapWidth) {
  349.         xOffset = pixPosition.x + iwWidth + iwOffsetX + padX - mapWidth;
  350.       }
  351.       if (this.alignBottom_) {
  352.         if (pixPosition.y < (-iwOffsetY + padY + iwHeight)) {
  353.           yOffset = pixPosition.y + iwOffsetY - padY - iwHeight;
  354.         } else if ((pixPosition.y + iwOffsetY + padY) > mapHeight) {
  355.           yOffset = pixPosition.y + iwOffsetY + padY - mapHeight;
  356.         }
  357.       } else {
  358.         if (pixPosition.y < (-iwOffsetY + padY)) {
  359.           yOffset = pixPosition.y + iwOffsetY - padY;
  360.         } else if ((pixPosition.y + iwHeight + iwOffsetY + padY) > mapHeight) {
  361.           yOffset = pixPosition.y + iwHeight + iwOffsetY + padY - mapHeight;
  362.         }
  363.       }
  364.  
  365.       if (!(xOffset === 0 && yOffset === 0)) {
  366.  
  367.         // Move the map to the shifted center.
  368.         //
  369.         var c = map.getCenter();
  370.         map.panBy(xOffset, yOffset);
  371.       }
  372.     }
  373.   }
  374. };
  375.  
  376. /**
  377.  * Sets the style of the InfoBox by setting the style sheet and applying
  378.  * other specific styles requested.
  379.  * @private
  380.  */
  381. InfoBox.prototype.setBoxStyle_ = function () {
  382.  
  383.   var i, boxStyle;
  384.  
  385.   if (this.div_) {
  386.  
  387.     // Apply style values from the style sheet defined in the boxClass parameter:
  388.     this.div_.className = this.boxClass_;
  389.  
  390.     // Clear existing inline style values:
  391.     this.div_.style.cssText = "";
  392.  
  393.     // Apply style values defined in the boxStyle parameter:
  394.     boxStyle = this.boxStyle_;
  395.     for (i in boxStyle) {
  396.  
  397.       if (boxStyle.hasOwnProperty(i)) {
  398.  
  399.         this.div_.style[i] = boxStyle[i];
  400.       }
  401.     }
  402.  
  403.     // Fix for iOS disappearing InfoBox problem.
  404.     // See http://stackoverflow.com/questions/9229535/google-maps-markers-disappear-at-certain-zoom-level-only-on-iphone-ipad
  405.     this.div_.style.WebkitTransform = "translateZ(0)";
  406.  
  407.     // Fix up opacity style for benefit of MSIE:
  408.     //
  409.     if (typeof this.div_.style.opacity !== "undefined" && this.div_.style.opacity !== "") {
  410.       // See http://www.quirksmode.org/css/opacity.html
  411.       this.div_.style.MsFilter = "\"progid:DXImageTransform.Microsoft.Alpha(Opacity=" + (this.div_.style.opacity * 100) + ")\"";
  412.       this.div_.style.filter = "alpha(opacity=" + (this.div_.style.opacity * 100) + ")";
  413.     }
  414.  
  415.     // Apply required styles:
  416.     //
  417.     this.div_.style.position = "absolute";
  418.     this.div_.style.visibility = 'hidden';
  419.     if (this.zIndex_ !== null) {
  420.  
  421.       this.div_.style.zIndex = this.zIndex_;
  422.     }
  423.   }
  424. };
  425.  
  426. /**
  427.  * Get the widths of the borders of the InfoBox.
  428.  * @private
  429.  * @return {Object} widths object (top, bottom left, right)
  430.  */
  431. InfoBox.prototype.getBoxWidths_ = function () {
  432.  
  433.   var computedStyle;
  434.   var bw = {top: 0, bottom: 0, left: 0, right: 0};
  435.   var box = this.div_;
  436.  
  437.   if (document.defaultView && document.defaultView.getComputedStyle) {
  438.  
  439.     computedStyle = box.ownerDocument.defaultView.getComputedStyle(box, "");
  440.  
  441.     if (computedStyle) {
  442.  
  443.       // The computed styles are always in pixel units (good!)
  444.       bw.top = parseInt(computedStyle.borderTopWidth, 10) || 0;
  445.       bw.bottom = parseInt(computedStyle.borderBottomWidth, 10) || 0;
  446.       bw.left = parseInt(computedStyle.borderLeftWidth, 10) || 0;
  447.       bw.right = parseInt(computedStyle.borderRightWidth, 10) || 0;
  448.     }
  449.  
  450.   } else if (document.documentElement.currentStyle) { // MSIE
  451.  
  452.     if (box.currentStyle) {
  453.  
  454.       // The current styles may not be in pixel units, but assume they are (bad!)
  455.       bw.top = parseInt(box.currentStyle.borderTopWidth, 10) || 0;
  456.       bw.bottom = parseInt(box.currentStyle.borderBottomWidth, 10) || 0;
  457.       bw.left = parseInt(box.currentStyle.borderLeftWidth, 10) || 0;
  458.       bw.right = parseInt(box.currentStyle.borderRightWidth, 10) || 0;
  459.     }
  460.   }
  461.  
  462.   return bw;
  463. };
  464.  
  465. /**
  466.  * Invoked when <tt>close</tt> is called. Do not call it directly.
  467.  */
  468. InfoBox.prototype.onRemove = function () {
  469.  
  470.   if (this.div_) {
  471.  
  472.     this.div_.parentNode.removeChild(this.div_);
  473.     this.div_ = null;
  474.   }
  475. };
  476.  
  477. /**
  478.  * Draws the InfoBox based on the current map projection and zoom level.
  479.  */
  480. InfoBox.prototype.draw = function () {
  481.  
  482.   this.createInfoBoxDiv_();
  483.  
  484.   var pixPosition = this.getProjection().fromLatLngToDivPixel(this.position_);
  485.  
  486.   this.div_.style.left = (pixPosition.x + this.pixelOffset_.width) + "px";
  487.  
  488.   if (this.alignBottom_) {
  489.     this.div_.style.bottom = -(pixPosition.y + this.pixelOffset_.height) + "px";
  490.   } else {
  491.     this.div_.style.top = (pixPosition.y + this.pixelOffset_.height) + "px";
  492.   }
  493.  
  494.   if (this.isHidden_) {
  495.  
  496.     this.div_.style.visibility = "hidden";
  497.  
  498.   } else {
  499.  
  500.     this.div_.style.visibility = "visible";
  501.   }
  502. };
  503.  
  504. /**
  505.  * Sets the options for the InfoBox. Note that changes to the <tt>maxWidth</tt>,
  506.  *  <tt>closeBoxMargin</tt>, <tt>closeBoxURL</tt>, and <tt>enableEventPropagation</tt>
  507.  *  properties have no affect until the current InfoBox is <tt>close</tt>d and a new one
  508.  *  is <tt>open</tt>ed.
  509.  * @param {InfoBoxOptions} opt_opts
  510.  */
  511. InfoBox.prototype.setOptions = function (opt_opts) {
  512.   if (typeof opt_opts.boxClass !== "undefined") { // Must be first
  513.  
  514.     this.boxClass_ = opt_opts.boxClass;
  515.     this.setBoxStyle_();
  516.   }
  517.   if (typeof opt_opts.boxStyle !== "undefined") { // Must be second
  518.  
  519.     this.boxStyle_ = opt_opts.boxStyle;
  520.     this.setBoxStyle_();
  521.   }
  522.   if (typeof opt_opts.content !== "undefined") {
  523.  
  524.     this.setContent(opt_opts.content);
  525.   }
  526.   if (typeof opt_opts.disableAutoPan !== "undefined") {
  527.  
  528.     this.disableAutoPan_ = opt_opts.disableAutoPan;
  529.   }
  530.   if (typeof opt_opts.maxWidth !== "undefined") {
  531.  
  532.     this.maxWidth_ = opt_opts.maxWidth;
  533.   }
  534.   if (typeof opt_opts.pixelOffset !== "undefined") {
  535.  
  536.     this.pixelOffset_ = opt_opts.pixelOffset;
  537.   }
  538.   if (typeof opt_opts.alignBottom !== "undefined") {
  539.  
  540.     this.alignBottom_ = opt_opts.alignBottom;
  541.   }
  542.   if (typeof opt_opts.position !== "undefined") {
  543.  
  544.     this.setPosition(opt_opts.position);
  545.   }
  546.   if (typeof opt_opts.zIndex !== "undefined") {
  547.  
  548.     this.setZIndex(opt_opts.zIndex);
  549.   }
  550.   if (typeof opt_opts.closeBoxMargin !== "undefined") {
  551.  
  552.     this.closeBoxMargin_ = opt_opts.closeBoxMargin;
  553.   }
  554.   if (typeof opt_opts.closeBoxURL !== "undefined") {
  555.  
  556.     this.closeBoxURL_ = opt_opts.closeBoxURL;
  557.   }
  558.   if (typeof opt_opts.infoBoxClearance !== "undefined") {
  559.  
  560.     this.infoBoxClearance_ = opt_opts.infoBoxClearance;
  561.   }
  562.   if (typeof opt_opts.isHidden !== "undefined") {
  563.  
  564.     this.isHidden_ = opt_opts.isHidden;
  565.   }
  566.   if (typeof opt_opts.visible !== "undefined") {
  567.  
  568.     this.isHidden_ = !opt_opts.visible;
  569.   }
  570.   if (typeof opt_opts.enableEventPropagation !== "undefined") {
  571.  
  572.     this.enableEventPropagation_ = opt_opts.enableEventPropagation;
  573.   }
  574.  
  575.   if (this.div_) {
  576.  
  577.     this.draw();
  578.   }
  579. };
  580.  
  581. /**
  582.  * Sets the content of the InfoBox.
  583.  *  The content can be plain text or an HTML DOM node.
  584.  * @param {string|Node} content
  585.  */
  586. InfoBox.prototype.setContent = function (content) {
  587.   this.content_ = content;
  588.  
  589.   if (this.div_) {
  590.  
  591.     if (this.closeListener_) {
  592.  
  593.       google.maps.event.removeListener(this.closeListener_);
  594.       this.closeListener_ = null;
  595.     }
  596.  
  597.     // Odd code required to make things work with MSIE.
  598.     //
  599.     if (!this.fixedWidthSet_) {
  600.  
  601.       this.div_.style.width = "";
  602.     }
  603.  
  604.     if (typeof content.nodeType === "undefined") {
  605.       this.div_.innerHTML = this.getCloseBoxImg_() + content;
  606.     } else {
  607.       this.div_.innerHTML = this.getCloseBoxImg_();
  608.       this.div_.appendChild(content);
  609.     }
  610.  
  611.     // Perverse code required to make things work with MSIE.
  612.     // (Ensures the close box does, in fact, float to the right.)
  613.     //
  614.     if (!this.fixedWidthSet_) {
  615.       this.div_.style.width = this.div_.offsetWidth + "px";
  616.       if (typeof content.nodeType === "undefined") {
  617.         this.div_.innerHTML = this.getCloseBoxImg_() + content;
  618.       } else {
  619.         this.div_.innerHTML = this.getCloseBoxImg_();
  620.         this.div_.appendChild(content);
  621.       }
  622.     }
  623.  
  624.     this.addClickHandler_();
  625.   }
  626.  
  627.   /**
  628.    * This event is fired when the content of the InfoBox changes.
  629.    * @name InfoBox#content_changed
  630.    * @event
  631.    */
  632.   google.maps.event.trigger(this, "content_changed");
  633. };
  634.  
  635. /**
  636.  * Sets the geographic location of the InfoBox.
  637.  * @param {LatLng} latlng
  638.  */
  639. InfoBox.prototype.setPosition = function (latlng) {
  640.  
  641.   this.position_ = latlng;
  642.  
  643.   if (this.div_) {
  644.  
  645.     this.draw();
  646.   }
  647.  
  648.   /**
  649.    * This event is fired when the position of the InfoBox changes.
  650.    * @name InfoBox#position_changed
  651.    * @event
  652.    */
  653.   google.maps.event.trigger(this, "position_changed");
  654. };
  655.  
  656. /**
  657.  * Sets the zIndex style for the InfoBox.
  658.  * @param {number} index
  659.  */
  660. InfoBox.prototype.setZIndex = function (index) {
  661.  
  662.   this.zIndex_ = index;
  663.  
  664.   if (this.div_) {
  665.  
  666.     this.div_.style.zIndex = index;
  667.   }
  668.  
  669.   /**
  670.    * This event is fired when the zIndex of the InfoBox changes.
  671.    * @name InfoBox#zindex_changed
  672.    * @event
  673.    */
  674.   google.maps.event.trigger(this, "zindex_changed");
  675. };
  676.  
  677. /**
  678.  * Sets the visibility of the InfoBox.
  679.  * @param {boolean} isVisible
  680.  */
  681. InfoBox.prototype.setVisible = function (isVisible) {
  682.  
  683.   this.isHidden_ = !isVisible;
  684.   if (this.div_) {
  685.     this.div_.style.visibility = (this.isHidden_ ? "hidden" : "visible");
  686.   }
  687. };
  688.  
  689. /**
  690.  * Returns the content of the InfoBox.
  691.  * @returns {string}
  692.  */
  693. InfoBox.prototype.getContent = function () {
  694.  
  695.   return this.content_;
  696. };
  697.  
  698. /**
  699.  * Returns the geographic location of the InfoBox.
  700.  * @returns {LatLng}
  701.  */
  702. InfoBox.prototype.getPosition = function () {
  703.  
  704.   return this.position_;
  705. };
  706.  
  707. /**
  708.  * Returns the zIndex for the InfoBox.
  709.  * @returns {number}
  710.  */
  711. InfoBox.prototype.getZIndex = function () {
  712.  
  713.   return this.zIndex_;
  714. };
  715.  
  716. /**
  717.  * Returns a flag indicating whether the InfoBox is visible.
  718.  * @returns {boolean}
  719.  */
  720. InfoBox.prototype.getVisible = function () {
  721.  
  722.   var isVisible;
  723.  
  724.   if ((typeof this.getMap() === "undefined") || (this.getMap() === null)) {
  725.     isVisible = false;
  726.   } else {
  727.     isVisible = !this.isHidden_;
  728.   }
  729.   return isVisible;
  730. };
  731.  
  732. /**
  733.  * Shows the InfoBox. [Deprecated; use <tt>setVisible</tt> instead.]
  734.  */
  735. InfoBox.prototype.show = function () {
  736.  
  737.   this.isHidden_ = false;
  738.   if (this.div_) {
  739.     this.div_.style.visibility = "visible";
  740.   }
  741. };
  742.  
  743. /**
  744.  * Hides the InfoBox. [Deprecated; use <tt>setVisible</tt> instead.]
  745.  */
  746. InfoBox.prototype.hide = function () {
  747.  
  748.   this.isHidden_ = true;
  749.   if (this.div_) {
  750.     this.div_.style.visibility = "hidden";
  751.   }
  752. };
  753.  
  754. /**
  755.  * Adds the InfoBox to the specified map or Street View panorama. If <tt>anchor</tt>
  756.  *  (usually a <tt>google.maps.Marker</tt>) is specified, the position
  757.  *  of the InfoBox is set to the position of the <tt>anchor</tt>. If the
  758.  *  anchor is dragged to a new location, the InfoBox moves as well.
  759.  * @param {Map|StreetViewPanorama} map
  760.  * @param {MVCObject} [anchor]
  761.  */
  762. InfoBox.prototype.open = function (map, anchor) {
  763.  
  764.   var me = this;
  765.  
  766.   if (anchor) {
  767.  
  768.     this.position_ = anchor.getPosition();
  769.     this.moveListener_ = google.maps.event.addListener(anchor, "position_changed", function () {
  770.       me.setPosition(this.getPosition());
  771.     });
  772.   }
  773.  
  774.   this.setMap(map);
  775.  
  776.   if (this.div_) {
  777.  
  778.     this.panBox_();
  779.   }
  780. };
  781.  
  782. /**
  783.  * Removes the InfoBox from the map.
  784.  */
  785. InfoBox.prototype.close = function () {
  786.  
  787.   var i;
  788.  
  789.   if (this.closeListener_) {
  790.  
  791.     google.maps.event.removeListener(this.closeListener_);
  792.     this.closeListener_ = null;
  793.   }
  794.  
  795.   if (this.eventListeners_) {
  796.    
  797.     for (i = 0; i < this.eventListeners_.length; i++) {
  798.  
  799.       google.maps.event.removeListener(this.eventListeners_[i]);
  800.     }
  801.     this.eventListeners_ = null;
  802.   }
  803.  
  804.   if (this.moveListener_) {
  805.  
  806.     google.maps.event.removeListener(this.moveListener_);
  807.     this.moveListener_ = null;
  808.   }
  809.  
  810.   if (this.contextListener_) {
  811.  
  812.     google.maps.event.removeListener(this.contextListener_);
  813.     this.contextListener_ = null;
  814.   }
  815.  
  816.   this.setMap(null);
  817. };
RAW Paste Data