diff --git a/src/lib/InfoWindow.js b/src/lib/InfoWindow.js index 17c94d14..82dc732f 100644 --- a/src/lib/InfoWindow.js +++ b/src/lib/InfoWindow.js @@ -1,77 +1,160 @@ +/* global google */ +import _ from "lodash"; + +import invariant from "invariant"; + import { default as React, - Component, PropTypes, + Children, } from "react"; import { - default as canUseDOM, -} from "can-use-dom"; + render, + unmountComponentAtNode, +} from "react-dom"; import { - default as InfoWindowCreator, - infoWindowDefaultPropTypes, - infoWindowControlledPropTypes, - infoWindowEventPropTypes, -} from "./creators/InfoWindowCreator"; - -import { default as GoogleMapHolder } from "./creators/GoogleMapHolder"; - -export default class InfoWindow extends Component { - static propTypes = { - // Uncontrolled default[props] - used only in componentDidMount - ...infoWindowDefaultPropTypes, - // Controlled [props] - used in componentDidMount/componentDidUpdate - ...infoWindowControlledPropTypes, - // Event [onEventName] - ...infoWindowEventPropTypes, - } + MAP, + ANCHOR, + INFO_WINDOW, +} from "./constants"; - static contextTypes = { - mapHolderRef: PropTypes.instanceOf(GoogleMapHolder), - } +import { + addDefaultPrefixToPropTypes, + collectUncontrolledAndControlledProps, + default as enhanceElement, +} from "./enhanceElement"; - // Public APIs +const controlledPropTypes = { + // NOTICE!!!!!! // - // https://developers.google.com/maps/documentation/javascript/3.exp/reference#InfoWindow + // Only expose those with getters & setters in the table as controlled props. // + // [].map.call($0.querySelectorAll("tr>td>code", function(it){ return it.textContent; }) + // .filter(function(it){ return it.match(/^set/) && !it.match(/^setMap/); }) + // + // https://developers.google.com/maps/documentation/javascript/3.exp/reference#InfoWindow + children: PropTypes.element, + options: PropTypes.object, + position: PropTypes.any, + zIndex: PropTypes.number, +}; + +const defaultUncontrolledPropTypes = addDefaultPrefixToPropTypes(controlledPropTypes); + +const eventMap = { + // https://developers.google.com/maps/documentation/javascript/3.exp/reference#InfoWindow // [].map.call($0.querySelectorAll("tr>td>code"), function(it){ return it.textContent; }) - // .filter(function(it){ return it.match(/^get/) && !it.match(/^getMap/); }) - getContent() { /* TODO: children */ } + onCloseClick: `closeclick`, + + onContentChanged: `content_changed`, - getPosition() { return this.state.infoWindow.getPosition(); } + onDomReady: `domready`, - getZIndex() { return this.state.infoWindow.getZIndex(); } - // END - Public APIs + onPositionChanged: `position_changed`, + + onZIndexChanged: `zindex_changed`, +}; + +const publicMethodMap = { + // Public APIs // // https://developers.google.com/maps/documentation/javascript/3.exp/reference#InfoWindow + // + // [].map.call($0.querySelectorAll("tr>td>code"), function(it){ return it.textContent; }) + // .filter(function(it){ return it.match(/^get/) && !it.match(/Map$/); }) + getPosition(infoWindow) { return infoWindow.getPosition(); }, - state = { + getZIndex(infoWindow) { return infoWindow.getZIndex(); }, + // END - Public APIs +}; + +const controlledPropUpdaterMap = { + children(infoWindow, children) { + render(Children.only(children), infoWindow.getContent()); + }, + options(infoWindow, options) { infoWindow.setOptions(options); }, + position(infoWindow, position) { infoWindow.setPosition(position); }, + zIndex(infoWindow, zIndex) { infoWindow.setZIndex(zIndex); }, +}; + +function getInstanceFromComponent(component) { + return component.state[INFO_WINDOW]; +} + +function openInfoWindow(context, infoWindow) { + const map = context[MAP]; + const anchor = context[ANCHOR]; + if (anchor) { + infoWindow.open(map, anchor); + } else if (infoWindow.getPosition()) { + infoWindow.open(map); + } else { + invariant(false, +`You must provide either an anchor (typically a ) or a position for .` + ); } +} - componentWillMount() { - const { mapHolderRef } = this.context; +export default _.flowRight( + React.createClass, + enhanceElement(getInstanceFromComponent, publicMethodMap, eventMap, controlledPropUpdaterMap), +)({ + displayName: `InfoWindow`, - if (!canUseDOM) { - return; - } - const infoWindow = InfoWindowCreator._createInfoWindow({ - ...this.props, - mapHolderRef, + propTypes: { + ...controlledPropTypes, + ...defaultUncontrolledPropTypes, + }, + + contextTypes: { + [MAP]: PropTypes.object, + [ANCHOR]: PropTypes.object, + }, + + getInitialState() { + const map = this.context[MAP]; + // https://developers.google.com/maps/documentation/javascript/3.exp/reference#InfoWindow + const infoWindow = new google.maps.InfoWindow({ + map, + ...collectUncontrolledAndControlledProps( + defaultUncontrolledPropTypes, + controlledPropTypes, + this.props + ), + // Override props of ReactElement type + content: document.createElement(`div`), + children: undefined, }); + openInfoWindow(this.context, infoWindow); + return { + [INFO_WINDOW]: infoWindow, + }; + }, - this.setState({ infoWindow }); - } + componentDidMount() { + const infoWindow = getInstanceFromComponent(this); + controlledPropUpdaterMap.children(infoWindow, this.props.children); + }, - render() { - if (this.state.infoWindow) { - return ( - - {this.props.children} - - ); - } else { - return (