Skip to content

Commit ee7396c

Browse files
committed
Merge pull request BetterBrief#17 from willmorgan/1.3-merge
1.3 skeleton
2 parents e8eb218 + a464849 commit ee7396c

File tree

5 files changed

+225
-56
lines changed

5 files changed

+225
-56
lines changed

README.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
1-
googlemapfield
1+
silverstripe-googlemapfield
22
==============
3-
Lets you record a precise location using latitude/longitude fields to a DataObject.
3+
4+
Lets you record a precise location using latitude/longitude/zoom fields to a DataObject.
45

56
Displays a map using the Google Maps API. The user may then choose where to place the marker; the landing coordinates are then saved.
67

78
You can also search for locations using the search box, which uses the Google Maps Geocoding API.
89

9-
Supports SilverStripe 3.1, 3.0 (branch "master") and 2.4 (branch "2.4")
10+
### Usage
11+
12+
##### `__construct` options
13+
14+
|Option|Default|Description|
15+
|------|-------|-----------|
16+
|`field_names`|See `GoogleMapField.yml`'s `default_options.field_names`|A map of field names to save the map data into your object.|
17+
18+
##### `Field` options
19+
20+
|Option|Default|Description|
21+
|------|-------|-----------|
22+
|`coords`|Your object's latitude and longitude|The intial coordinates of the map - note: this is not the default value if no object exists|
23+
|`map`|Zoom of 14, map type of ROADMAP|A [google.maps.MapOptions](https://developers.google.com/maps/documentation/javascript/reference?csw=1#MapOptions) object|

_config/googlemapfield.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
GoogleMapField:
2+
default_options:
3+
api_key: null
4+
show_search_box: true
5+
field_names:
6+
Latitude: 'Latitude'
7+
Longitude: 'Longitude'
8+
Zoom: 'Zoom'
9+
map:
10+
zoom: 14
11+
default_field_values:
12+
Latitude: 30
13+
Longitude: 0

code/GoogleMapField.php

Lines changed: 184 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,38 @@
11
<?php
22

3+
/**
4+
* GoogleMapField
5+
* Lets you record a precise location using latitude/longitude fields to a
6+
* DataObject. Displays a map using the Google Maps API. The user may then
7+
* choose where to place the marker; the landing coordinates are then saved.
8+
* You can also search for locations using the search box, which uses the Google
9+
* Maps Geocoding API.
10+
* @author <@willmorgan>
11+
*/
312
class GoogleMapField extends FormField {
413

5-
protected
6-
$data,
7-
$latField,
8-
$lngField,
9-
$options = array();
10-
11-
protected static
12-
$defaults = array(
13-
'fieldNames' => array(
14-
'lat' => 'Lat',
15-
'lng' => 'Lng',
16-
),
17-
'showSearchBox' => true,
18-
'apikey' => null,
19-
),
20-
$js_inserted = false;
14+
protected $data;
15+
16+
/**
17+
* @var FormField
18+
*/
19+
protected $latField;
20+
21+
/**
22+
* @var FormField
23+
*/
24+
protected $lngField;
25+
26+
/**
27+
* @var FormField
28+
*/
29+
protected $zoomField;
30+
31+
/**
32+
* The merged version of the default and user specified options
33+
* @var array
34+
*/
35+
protected $options = array();
2136

2237
/**
2338
* @param DataObject $data The controlling dataobject
@@ -28,82 +43,194 @@ public function __construct(DataObject $data, $title, $options = array()) {
2843
$this->data = $data;
2944

3045
// Set up fieldnames
31-
$this->options = array_merge(self::$defaults, $options);
46+
$this->setupOptions($options);
47+
48+
$this->setupChildren();
49+
50+
parent::__construct($this->getName(), $title);
51+
}
52+
53+
// Auto generate a name
54+
public function getName() {
55+
$fieldNames = $this->getOption('field_names');
56+
return sprintf(
57+
'%s_%s_%s',
58+
$this->data->class,
59+
$fieldNames['Latitude'],
60+
$fieldNames['Longitude']
61+
);
62+
}
3263

33-
$fieldNames = $this->getOption('fieldNames');
64+
/**
65+
* Merge options preserving the first level of array keys
66+
* @param array $options
67+
*/
68+
public function setupOptions(array $options) {
69+
$this->options = static::config()->default_options;
70+
foreach($this->options as $name => &$value) {
71+
if(isset($options[$name])) {
72+
if(is_array($value)) {
73+
$value = array_merge($value, $options[$name]);
74+
}
75+
else {
76+
$value = $options[$name];
77+
}
78+
}
79+
}
80+
}
3481

35-
// Auto generate a name
36-
$name = sprintf('%s_%s_%s', $data->class, $fieldNames['lat'], $fieldNames['lng']);
82+
/**
83+
* Set up child hidden fields, and optionally the search box.
84+
* @return FieldList the children
85+
*/
86+
public function setupChildren() {
87+
$name = $this->getName();
3788

3889
// Create the latitude/longitude hidden fields
90+
$this->latField = HiddenField::create(
91+
$name.'[Latitude]',
92+
'Lat',
93+
$this->recordFieldData('Latitude')
94+
)->addExtraClass('googlemapfield-latfield');
95+
96+
$this->lngField = HiddenField::create(
97+
$name.'[Longitude]',
98+
'Lng',
99+
$this->recordFieldData('Longitude')
100+
)->addExtraClass('googlemapfield-lngfield');
101+
102+
$this->zoomField = HiddenField::create(
103+
$name.'[Zoom]',
104+
'Zoom',
105+
$this->recordFieldData('Zoom')
106+
)->addExtraClass('googlemapfield-zoomfield');
107+
39108
$this->children = new FieldList(
40-
$this->latField = HiddenField::create($name . '[' . $fieldNames['lat'] . ']', 'Lat', $this->getLatData())->addExtraClass('googlemapfield-latfield'),
41-
$this->lngField = HiddenField::create($name . '[' . $fieldNames['lng'] . ']', 'Lng', $this->getLngData())->addExtraClass('googlemapfield-lngfield'),
42-
TextField::create('Search')
109+
$this->latField,
110+
$this->lngField,
111+
$this->zoomField
112+
);
113+
114+
if($this->options['show_search_box']) {
115+
$this->children->push(
116+
TextField::create('Search')
43117
->addExtraClass('googlemapfield-searchfield')
44118
->setAttribute('placeholder', 'Search for a location')
45-
);
119+
);
120+
}
46121

47-
parent::__construct($name, $title);
122+
return $this->children;
48123
}
49124

125+
/**
126+
* @param array $properties
127+
* @see https://developers.google.com/maps/documentation/javascript/reference
128+
* {@inheritdoc}
129+
*/
50130
public function Field($properties = array()) {
51-
$key = $this->options['apikey'] ? "&key=".$this->options['apikey'] : "";
52-
Requirements::javascript(GOOGLEMAPFIELD_BASE .'/javascript/GoogleMapField.js');
53-
Requirements::javascript("//maps.googleapis.com/maps/api/js?callback=googlemapfieldInit".$key);
54-
Requirements::css(GOOGLEMAPFIELD_BASE .'/css/GoogleMapField.css');
55131
$jsOptions = array(
56-
'coords' => array($this->getLatData(), $this->getLngData()),
132+
'coords' => array(
133+
$this->recordFieldData('Latitude'),
134+
$this->recordFieldData('Longitude')
135+
),
57136
'map' => array(
58-
'zoom' => 8,
137+
'zoom' => $this->recordFieldData('Zoom') ?: $this->getOption('map.zoom'),
59138
'mapTypeId' => 'ROADMAP',
60139
),
61140
);
62-
if(!$this->options['showSearchBox']){
63-
$this->children->removeByName("Search");
64-
}
65-
$jsOptions = array_replace_recursive($jsOptions, $this->options);
66-
$this->setAttribute('data-settings', Convert::array2json($jsOptions));
67141

142+
$jsOptions = array_replace_recursive($this->options, $jsOptions);
143+
$this->setAttribute('data-settings', Convert::array2json($jsOptions));
144+
$this->requireDependencies();
68145
return parent::Field($properties);
69146
}
70147

71-
function setValue($value) {
72-
$this->latField->setValue($value[$this->getLatField()]);
73-
$this->lngField->setValue($value[$this->getLngField()]);
148+
/**
149+
* Set up and include any frontend requirements
150+
* @return void
151+
*/
152+
protected function requireDependencies() {
153+
$gmapsParams = array(
154+
'callback' => 'googlemapfieldInit',
155+
);
156+
if($key = $this->getOption('api_key')) {
157+
$gmapsParams['key'] = $key;
158+
}
159+
Requirements::css(GOOGLEMAPFIELD_BASE .'/css/GoogleMapField.css');
160+
Requirements::javascript(GOOGLEMAPFIELD_BASE .'/javascript/GoogleMapField.js');
161+
Requirements::javascript('//maps.googleapis.com/maps/api/js?' . http_build_query($gmapsParams));
162+
}
163+
164+
/**
165+
* {@inheritdoc}
166+
*/
167+
public function setValue($record) {
168+
$this->latField->setValue(
169+
$record['Latitude']
170+
);
171+
$this->lngField->setValue(
172+
$record['Longitude']
173+
);
174+
$this->zoomField->setValue(
175+
$record['Zoom']
176+
);
74177
return $this;
75178
}
76179

180+
/**
181+
* Take the latitude/longitude fields and save them to the DataObject.
182+
* {@inheritdoc}
183+
*/
77184
public function saveInto(DataObjectInterface $record) {
78-
$record->setCastedField($this->getLatField(), $this->latField->dataValue());
79-
$record->setCastedField($this->getLngField(), $this->lngField->dataValue());
185+
$record->setCastedField($this->childFieldName('Latitude'), $this->latField->dataValue());
186+
$record->setCastedField($this->childFieldName('Longitude'), $this->lngField->dataValue());
187+
$record->setCastedField($this->childFieldName('Zoom'), $this->zoomField->dataValue());
80188
return $this;
81189
}
82190

191+
/**
192+
* @return FieldList The Latitude/Longitude fields
193+
*/
83194
public function getChildFields() {
84195
return $this->children;
85196
}
86197

87-
public function getLatField() {
88-
$fieldNames = $this->getOption('fieldNames');
89-
return $fieldNames['lat'];
198+
protected function childFieldName($name) {
199+
$fieldNames = $this->getOption('field_names');
200+
return $fieldNames[$name];
201+
}
202+
203+
protected function recordFieldData($name) {
204+
$fieldName = $this->childFieldName($name);
205+
return $this->data->$fieldName ?: $this->getDefaultValue($name);
90206
}
91207

92-
public function getLngField() {
93-
$fieldNames = $this->getOption('fieldNames');
94-
return $fieldNames['lng'];
208+
public function getDefaultValue($name) {
209+
$fieldValues = $this->getOption('default_field_values');
210+
return isset($fieldValues[$name]) ? $fieldValues[$name] : null;
95211
}
96212

213+
/**
214+
* @return string The VALUE of the Latitude field
215+
*/
97216
public function getLatData() {
98-
$fieldNames = $this->getOption('fieldNames');
99-
return $this->data->$fieldNames['lat'];
217+
$fieldNames = $this->getOption('field_names');
218+
return $this->data->$fieldNames['Latitude'];
100219
}
101220

221+
/**
222+
* @return string The VALUE of the Longitude field
223+
*/
102224
public function getLngData() {
103-
$fieldNames = $this->getOption('fieldNames');
104-
return $this->data->$fieldNames['lng'];
225+
$fieldNames = $this->getOption('field_names');
226+
return $this->data->$fieldNames['Longitude'];
105227
}
106228

229+
/**
230+
* Get the merged option that was set on __construct
231+
* @param string $name The name of the option
232+
* @return mixed
233+
*/
107234
public function getOption($name) {
108235
// Quicker execution path for "."-free names
109236
if (strpos($name, '.') === false) {
@@ -124,6 +251,12 @@ public function getOption($name) {
124251
}
125252
}
126253

254+
/**
255+
* Set an option for this field
256+
* @param string $name The name of the option to set
257+
* @param mixed $val The value of said option
258+
* @return $this
259+
*/
127260
public function setOption($name, $val) {
128261
// Quicker execution path for "."-free names
129262
if(strpos($name,'.') === false) {

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"name": "betterbrief/silverstripe-googlemapfield",
33
"type": "silverstripe-module",
44
"description": "Save locations using latitude/longitude DataObject fields.",
5+
"version": "1.3",
56
"keywords": ["maps","google", "googlemapfield", "silverstripe", "map", "geolocation"],
67
"homepage": "http://github.com/BetterBrief/googlemapfield",
78
"license": "BSD",

javascript/GoogleMapField.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* GoogleMapField.js
3-
* @author Will Morgan <[email protected]>
3+
* @author <@willmorgan>
44
*/
55
(function($) {
66

@@ -14,7 +14,7 @@
1414
centre = new google.maps.LatLng(options.coords[0], options.coords[1]),
1515
options = {
1616
streetViewControl: false,
17-
zoom: options.map.zoom,
17+
zoom: options.map.zoom * 1,
1818
center: centre,
1919
mapTypeId: google.maps.MapTypeId[options.map.mapTypeId]
2020
},
@@ -28,6 +28,7 @@
2828
}),
2929
latField = field.find('.googlemapfield-latfield'),
3030
lngField = field.find('.googlemapfield-lngfield'),
31+
zoomField = field.find('.googlemapfield-zoomfield'),
3132
search = field.find('.googlemapfield-searchfield');
3233

3334
// Update the hidden fields and mark as changed
@@ -39,12 +40,17 @@
3940

4041
latField.val(latCoord);
4142
lngField.val(lngCoord);
43+
4244
if (!init) {
4345
// Mark as changed(?)
4446
$('.cms-edit-form').addClass('changed');
4547
}
4648
}
4749

50+
function updateZoom() {
51+
zoomField.val(map.getZoom());
52+
}
53+
4854
function centreOnMarker() {
4955
var center = marker.getPosition();
5056
map.panTo(center);
@@ -84,6 +90,8 @@
8490

8591
google.maps.event.addListener(map, 'click', mapClicked);
8692

93+
google.maps.event.addListener(map, 'zoom_changed', updateZoom);
94+
8795
search.on({
8896
'change': searchReady,
8997
'keydown': function(ev) {

0 commit comments

Comments
 (0)