Skip to content

Commit

Permalink
Merge pull request #5 from asennikov/infowindow-component
Browse files Browse the repository at this point in the history
Independent Info Window component
  • Loading branch information
asennikov committed Oct 19, 2015
2 parents 69c281c + b5ff966 commit 8e9225f
Show file tree
Hide file tree
Showing 11 changed files with 508 additions and 116 deletions.
41 changes: 33 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,31 @@ with the main `g-map` component.
{{/g-map}}
```

## Map with Info Windows

Those Info Windows will be open right after component is rendered
and will be closed forever after user closes them. You can specify
optional `onClose` action to tear down anything you need when Info Window
has been closed by user.

```handlebars
{{#g-map lat=37.7833 lng=-122.4167 zoom=12 as |context|}}
{{#g-map-infowindow context lat=37.7733 lng=-122.4067}}
<h1>Info Window with Block</h1>
<p>Text with {{bound}} variables</p>
<button {{action "do"}}>Do</button>
{{/g-map-infowindow}}
{{g-map-infowindow context lat=37.7733 lng=-122.4067
title="Blockless form" message="Plain text."}}
{{g-map-infowindow context lat=37.7733 lng=-122.4067
title="With action set"
onClose="myOnCloseAction"}}
{{g-map-infowindow context lat=37.7733 lng=-122.4067
title="With closure action set"
onClose=(action "myOnCloseAction")}}
{{/g-map}}
```

## Map fits to show all initial Markers

`shouldFit` attribute overrides `lat`, `lng`, `zoom` settings.
Expand All @@ -65,19 +90,19 @@ with the main `g-map` component.
{{/g-map}}
```

## Map with Markers and optional Info Windows
## Map with Markers and bound Info Windows

Markers can have optional Info Windows activated on click.
To provide content for Info Window you should call `g-map-marker`
in block form with `withInfowindow` flag set to `true`.
Markers can have bound Info Windows activated on click.
To properly bind Info Window with Marker you should call `g-map-marker`
in block form and set context of Info Window to the one provided by Marker.

```handlebars
{{#g-map lat=37.7833 lng=-122.4167 zoom=12 as |context|}}
{{g-map-marker context lat=37.7933 lng=-122.4167}}
{{#g-map-marker context lat=37.7833 lng=-122.4267 withInfowindow=true}}
<h2>Infowindow header</h2>
<p>Text with {{bound}} variables</p>
<button {{action "do"}}>Do</button>
{{#g-map-marker context lat=37.7833 lng=-122.4267 as |markerContext|}}
{{#g-map-infowindow markerContext}}
<h2>Bound Info Window</h2>
{{/g-map-infowindow}}
{{/g-map-marker}}
{{/g-map}}
```
Expand Down
120 changes: 120 additions & 0 deletions addon/components/g-map-infowindow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import Ember from 'ember';
import layout from '../templates/components/g-map-infowindow';
import GMapComponent from './g-map';
import GMapMarkerComponent from './g-map-marker';

const { isEmpty, isPresent, observer, computed, run, assert, typeOf } = Ember;

const GMapInfowindowComponent = Ember.Component.extend({
layout: layout,
classNames: ['g-map-marker'],

map: computed.alias('mapContext.map'),
marker: computed.alias('mapContext.marker'),

init() {
this._super(arguments);

let mapContext = this.get('mapContext');
let hasMap = mapContext instanceof GMapComponent;
let hasMarker = mapContext instanceof GMapMarkerComponent;
assert('Must be inside {{#g-map}} or {{#g-map-marker}} components with context set',
hasMarker || hasMap);

this.set('hasMarker', hasMarker);
},

didInsertElement() {
this._super();
if (isEmpty(this.get('infowindow'))) {
let infowindow = this.buildInfowindow();
this.set('infowindow', infowindow);
}
this.setPosition();
this.setMap();
this.setMarker();
},

willDestroyElement() {
this.close();
},

buildInfowindow() {
let infowindow = new google.maps.InfoWindow({
content: this.get('element'),
disableAutoPan: true
});

if (isPresent(this.get('attrs.onClose'))) {
this.attachCloseEvent(infowindow);
}
return infowindow;
},

attachCloseEvent(infowindow) {
infowindow.addListener('closeclick', () => {
const { onClose } = this.attrs;
if (typeOf(onClose) === 'function') {
onClose();
} else {
this.sendAction('onClose');
}
});
},

close() {
let infowindow = this.get('infowindow');
if (isPresent(infowindow)) {
infowindow.close();
}
},

mapWasSet: observer('map', function() {
run.once(this, 'setMap');
}),

setMap() {
let map = this.get('map');
let hasMarker = this.get('hasMarker');
let infowindow = this.get('infowindow');

if (isPresent(infowindow) && isPresent(map) && !hasMarker) {
infowindow.open(map);
}
},

markerWasSet: observer('marker', function() {
run.once(this, 'setMarker');
}),

setMarker() {
let map = this.get('map');
let marker = this.get('marker');
let infowindow = this.get('infowindow');

if (isPresent(infowindow) && isPresent(map) && isPresent(marker)) {
marker.addListener('click', () => infowindow.open(map, marker));
}
},

coordsChanged: observer('lat', 'lng', function() {
run.once(this, 'setPosition');
}),

setPosition() {
let infowindow = this.get('infowindow');
let lat = this.get('lat');
let lng = this.get('lng');

if (isPresent(infowindow) && isPresent(lat) && isPresent(lng)) {
let position = new google.maps.LatLng(lat, lng);
infowindow.setPosition(position);
}
}
});

GMapInfowindowComponent.reopenClass({
positionalParams: ['mapContext']
});

export default GMapInfowindowComponent;
20 changes: 0 additions & 20 deletions addon/components/g-map-marker.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ const GMapMarkerComponent = Ember.Component.extend({
let mapContext = this.get('mapContext');
assert('Must be inside {{#g-map}} component with context set', mapContext instanceof GMapComponent);

if (isEmpty(this.get('withInfowindow'))) {
this.set('withInfowindow', false);
}
this.register();
},

Expand Down Expand Up @@ -63,23 +60,6 @@ const GMapMarkerComponent = Ember.Component.extend({

if (isPresent(marker) && isPresent(map)) {
marker.setMap(map);
if (this.get('withInfowindow')) {
this.setInfowindow();
}
}
},

setInfowindow() {
let map = this.get('map');
let marker = this.get('marker');

if (isPresent(marker) && isPresent(map)) {
let infowindow = new google.maps.InfoWindow({
content: this.get('element')
});
marker.addListener('click', function() {
infowindow.open(map, marker);
});
}
},

Expand Down
6 changes: 6 additions & 0 deletions addon/templates/components/g-map-infowindow.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{{#if hasBlock}}
{{yield}}
{{else}}
<h1>{{title}}</h1>
<p>{{message}}</p>
{{/if}}
2 changes: 1 addition & 1 deletion addon/templates/components/g-map-marker.hbs
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{{yield}}
{{yield this}}
1 change: 1 addition & 0 deletions app/components/g-map-infowindow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from 'ember-g-map/components/g-map-infowindow';
14 changes: 4 additions & 10 deletions tests/dummy/app/controllers/application.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import Ember from 'ember';

export default Ember.Controller.extend({
firstMarker: {
lat: 37.7933,
lng: -122.4167
},

secondMarker: {
lat: 37.7733,
lng: -122.4167
},

randomVariable: 111,

actions: {
refresh() {
this.set('randomVariable', Math.floor(Math.random() * 1000));
},

onInfowindowClosed() {
window.alert('Info Window Closed!');
}
}
});
29 changes: 20 additions & 9 deletions tests/dummy/app/templates/application.hbs
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
<h2 id="title">Ember-g-map Component</h2>

{{#g-map shouldFit=true as |context|}}
{{g-map-marker context lat=37.7933 lng=-122.4167}}
{{g-map-marker context lat=37.7933 lng=-122.4467}}

{{#g-map-marker context lat=37.7733 lng=-122.4167 withInfowindow=true}}
<h1>Pretty Infowindow!</h1>
<p>It can has bound variables:</p>
<p>Random: {{randomVariable}}</p>
{{#g-map-marker context lat=37.7433 lng=-122.3867 as |markerContext|}}
{{#g-map-infowindow markerContext}}
<h1>Bound InfoWindow</h1>
<p>This InfoWindow is bound to a marker.</p>
<p>It can has bound variables:</p>
<p>Random: {{randomVariable}}</p>

<p>And elements with actions:</p>
<button {{action "refresh"}}>Refresh</button>
<p>And elements with actions:</p>
<button {{action "refresh"}}>Refresh</button>
{{/g-map-infowindow}}
{{/g-map-marker}}

{{#g-map-infowindow context lat=37.7333 lng=-122.4367 onClose="onInfowindowClosed"}}
<h1>Independent InfoWindow</h1>
<p>This InfoWindow can be placed anywhere on the map.</p>
{{/g-map-infowindow}}

{{g-map-infowindow context title="Blockless Infowindow" message="Contains plain text"
lat=37.7633 lng=-122.4367 onClose=(action "onInfowindowClosed")}}

{{g-map-route context
originLat=37.7933 originLng=-122.4167
destinationLat=37.7733 destinationLng=-122.4167}}
originLat=37.7933 originLng=-122.4467
destinationLat=37.7433 destinationLng=-122.3867}}
{{/g-map}}
54 changes: 54 additions & 0 deletions tests/integration/components/g-map-infowindow-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';

moduleForComponent('g-map-infowindow', 'Integration | Component | g map infowindow', {
integration: true
});

test('it renders inside {{g-map}} component', function(assert) {
assert.expect(2);

this.render(hbs`
{{#g-map as |context|}}
{{g-map-infowindow context}}
{{/g-map}}
`);

assert.equal(this.$().text().trim(), '');

this.render(hbs`
{{#g-map as |context|}}
{{#g-map-infowindow context}}
template block text
{{/g-map-infowindow}}
{{/g-map}}
`);

assert.equal(this.$().text().trim(), 'template block text');
});

test('it renders inside {{g-map-marker}} component', function(assert) {
assert.expect(2);

this.render(hbs`
{{#g-map as |context|}}
{{#g-map-marker context as |markerContext|}}
{{g-map-infowindow markerContext}}
{{/g-map-marker}}
{{/g-map}}
`);

assert.equal(this.$().text().trim(), '');

this.render(hbs`
{{#g-map as |context|}}
{{#g-map-marker context as |markerContext|}}
{{#g-map-infowindow markerContext}}
template block text
{{/g-map-infowindow}}
{{/g-map-marker}}
{{/g-map}}
`);

assert.equal(this.$().text().trim(), 'template block text');
});
Loading

0 comments on commit 8e9225f

Please sign in to comment.