/
slt-cf-gmaps.js
403 lines (263 loc) · 13.4 KB
/
slt-cf-gmaps.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
// Google Maps script for Developer's Custom Fields
// Contributed by adriantoll
// Be careful of center (in this script) / centre (DCF form field IDs)
/* global google, slt_cf_gmaps, alert */
/* exported slt_cf_gmap_init */
// Set up array for multiple maps and markers
var slt_cf_maps = [];
// Function to write a marker array to hidden input with a pipe as delimiter
function write_markers(container_id) {
// Start with an empty string
var markers_string = '';
// Loop through the markers
for (var key in slt_cf_maps[container_id].markers) {
// Get the marker latlng as a string
var marker_latlng = slt_cf_maps[container_id].markers[key].getPosition().toString();
// Add this marker to the HTML string
markers_string += marker_latlng;
}
// Replace ")(" with "|", then remove all other brackets and spaces
markers_string = markers_string.replace(/\)\(/g,'|').replace(/\(/g,'').replace(/\)/g,'').replace(/ /g,'');
// Write to the input
document.getElementById(container_id + '_map_markers').value = markers_string;
}
// Function to add a marker to a map
function add_marker(container_id,new_marker_latlng) {
// Set the marker var here to avoid duplicate
// definition errors in jshint
var marker;
// If it's not an input map
if (slt_cf_maps[container_id].settings.input_map === false) {
// Add a simple marker to the map
marker = new google.maps.Marker({
map: slt_cf_maps[container_id].map,
position: new_marker_latlng,
});
}
// Otherwise it's an input map
else {
// Only add a marker if we haven't reached the maximum number of markers
// or if this is a map being initialised
if ( slt_cf_maps[container_id].markers.length < slt_cf_maps[container_id].settings.markers_max || slt_cf_maps[container_id].settings.init === true ) {
// Add an interactive marker to the map
// by pushing it to the markers object
slt_cf_maps[container_id].markers.push(
new google.maps.Marker({
draggable: true,
map: slt_cf_maps[container_id].map,
position: new_marker_latlng,
title: 'Drag to move, click to delete',
})
);
// Update the <input> array
write_markers(container_id);
// Get the marker's array key
var marker_key = slt_cf_maps[container_id].markers.length - 1;
// Set an event listener for a click on the marker
google.maps.event.addListener(slt_cf_maps[container_id].markers[marker_key], 'click', function() {
// Remove the marker from the array
slt_cf_maps[container_id].markers.splice(marker_key,1);
// Remove the marker from the map
this.setMap(null);
// Remove a "max markers" error highlight
if (slt_cf_maps[container_id].settings.markers_max > 0) { document.getElementById('markers_max_message').className = ''; }
// Update the <input> array
write_markers(container_id);
});
// Set an event listener for the end of a marker being dragged
google.maps.event.addListener(slt_cf_maps[container_id].markers[marker_key], 'dragend', function(e) {
// Update the <input> array
write_markers(container_id);
});
// Otherwise highlight the max markers message
} else if (slt_cf_maps[container_id].settings.markers_max > 1) {
document.getElementById('markers_max_message').className = 'markers_max_message_error';
}
}
}
// Write out a map for input or output
function slt_cf_gmap_init( container_id, map_mode, markers_max, map_markers, map_center_latlng, map_zoom, gmap_type, callback ) {
// Set the map type
if (gmap_type === 'hybrid') { gmap_type = google.maps.MapTypeId.HYBRID; }
else if (gmap_type === 'satellite') { gmap_type = google.maps.MapTypeId.SATELLITE; }
else if (gmap_type === 'terrain') { gmap_type = google.maps.MapTypeId.TERRAIN; }
else { gmap_type = google.maps.MapTypeId.ROADMAP; }
// Set the map center
map_center_latlng = map_center_latlng.replace(' ','');
map_center_latlng = map_center_latlng.split(',');
map_center_latlng = new google.maps.LatLng(map_center_latlng[0],map_center_latlng[1]);
// Put the options array together
var map_options = {
center: map_center_latlng,
mapTypeId: gmap_type,
scrollwheel: false,
zoom: map_zoom,
};
// Write the map
slt_cf_maps[container_id] = [];
slt_cf_maps[container_id].map = new google.maps.Map(document.getElementById( container_id ), map_options);
// Add objects to the container for markers and settings
slt_cf_maps[container_id].markers = [];
slt_cf_maps[container_id].settings = [];
// Add an init variable so we don't crash when reducing max markers
slt_cf_maps[container_id].settings.init = true;
// Set the container_id as a variable in the map object
// to write changes out to the container HTML
slt_cf_maps[container_id].map.parent_container_id = container_id;
// Set the maximum number of markers
slt_cf_maps[container_id].settings.markers_max = markers_max;
// Store whether the map is an input map or not
if (map_mode === 'input') { slt_cf_maps[container_id].settings.input_map = true; }
else { slt_cf_maps[container_id].settings.input_map = false; }
// Extra settings for markers
if (markers_max) {
// If there are existing markers
if (map_markers.length > 0) {
// Loop through the markers
for (var key in map_markers) {
// Filter unwanted properties from the prototype
if (map_markers.hasOwnProperty(key)) {
// Split the latlng
var existing_marker_latlng = map_markers[key].split(',');
// Create a new latlng object
existing_marker_latlng = new google.maps.LatLng( existing_marker_latlng[0], existing_marker_latlng[1] );
// Add the marker
add_marker(container_id, existing_marker_latlng);
}
}
}
// Only do this on input maps
if (map_mode === 'input') {
// Set a variable to store double click status
slt_cf_maps[container_id].settings.doubleClick = false;
// Function to deal with double clicks
google.maps.event.addListener( slt_cf_maps[container_id].map, 'dblclick', function() {
// Set the double click status to true so single click functions doesn't get triggered
slt_cf_maps[container_id].settings.doubleClick = true;
// Reset double click status once the delay for a potential single click has passed
window.setTimeout(function(){ slt_cf_maps[container_id].settings.doubleClick = false; }, 250);
});
// Listen for a click on the map
google.maps.event.addListener(slt_cf_maps[container_id].map, 'click', function(e) {
// Wait 250ms to see if there's a double click
window.setTimeout(function(){ if (!slt_cf_maps[container_id].settings.doubleClick) {
// Add the marker to the map
add_marker(container_id, e.latLng);
} }, 250);
});
}
}
// Extra settings for input maps
if (map_mode === 'input') {
// Listen for changes to the map bounds
google.maps.event.addListener( slt_cf_maps[container_id].map, 'bounds_changed', function() {
// Write the new zoom, center and bounds for saving with the post
document.getElementById( this.parent_container_id + '_zoom' ).value = this.getZoom();
document.getElementById( this.parent_container_id + '_centre_latlng' ).value = this.getCenter().toString().slice(1,-1).replace(' ','');
document.getElementById( this.parent_container_id + '_bounds_sw').value = this.getBounds().getSouthWest().toString().slice(1,-1).replace(' ','');
document.getElementById( this.parent_container_id + '_bounds_ne').value = this.getBounds().getNorthEast().toString().slice(1,-1).replace(' ','');
});
// Geocoder
if ( jQuery().autocomplete ) {
// Initialise the geocoder
var geocoder = new google.maps.Geocoder();
// Kick off the geocoder on page load
jQuery( document ).ready( function( $ ) {
// Check if we can use the placeholder instead of a label
var gmap_geocoder_label_class = '';
if (document.createElement('input').placeholder !== 'undefined') {
gmap_geocoder_label_class = 'screen-reader-text';
}
// Make the marker instructions conditional
var marker_instructions = '';
if (markers_max) {
marker_instructions = '';
if ( slt_cf_maps[container_id].settings.markers_max > 1 ) {
marker_instructions += '<p>Click on the map or find an address to add a marker. Click a marker to remove it. Drag and drop a marker to change its location.</p>';
marker_instructions += '<p id="markers_max_message">Maximum number of markers: ' + slt_cf_maps[container_id].settings.markers_max + '</p>';
}
else {
marker_instructions += '<p> Drag and drop the marker or find an address below.</p>';
}
}
// Write the autocomplete form
$( '#' + container_id ).after( '<p class="gmap-address">' + marker_instructions + '<label for="' + container_id + '_address" class="' + gmap_geocoder_label_class + '">' + slt_cf_gmaps.geocoder_label + ':</label><input type="text" id="' + container_id + '_address" name="' + container_id + '_address" value="" class="regular-text" style="width:100%;" placeholder="Find an address" /></p>' );
// Activate the autocomplete functionality
$( '#' + container_id + '_address' ).autocomplete({
// Fetch the address values
source: function(request, response) {
// Geocode the responses
// 'bounds' biases the response to results within the existing map bounds
// https://developers.google.com/maps/documentation/geocoding/#geocoding
geocoder.geocode( {'address': request.term, 'bounds': slt_cf_maps[container_id].map.getBounds() }, function(results, status) {
// If we get meaningful results
if (status === google.maps.GeocoderStatus.OK) {
// Go through each response
response($.map(results, function(item) {
// Return the address values
return {
label: item.formatted_address,
value: item.formatted_address,
latitude: item.geometry.location.lat(),
longitude: item.geometry.location.lng()
};
}));
}
// Otherwise there's a problem
else { console.log('Geocode was not successful for the following reason: ' + status); }
});
},
// When an address is selected
select: function(event, ui) {
// Get the latlng of the geocode result
var newLocation = new google.maps.LatLng(ui.item.latitude,ui.item.longitude);
// Recenter the map
slt_cf_maps[container_id].map.panTo(newLocation);
// If there are multiple markers
if ( slt_cf_maps[container_id].settings.markers_max > 1 ){
// Try to add a new marker
add_marker(container_id,newLocation);
// Or if there's one marker
} else if ( slt_cf_maps[container_id].settings.markers_max === 1 ) {
// Move the marker
slt_cf_maps[container_id].markers[0].setPosition(newLocation);
// And update the <input> array
write_markers(container_id);
}
}
});
});
}
}
// If there's a callback, call it with a reference to the map
if ( typeof callback !== 'undefined' && window[callback] ) { window[callback]( slt_cf_maps[container_id].map ); }
// We've finished, so init is no longer true
slt_cf_maps[container_id].settings.init = false;
}
// HIDE AND SHOW MAPS
// Wait for the document to load
jQuery( document ).ready( function( $ ) {
// Listen for a change to the display radio buttons
$('input.gmap_toggle_display').change( function() {
// Set the map container id and wrapper selector
var map_container_id = $(this).attr('data-map-id');
var map_wrapper_selector = '#' + map_container_id + '_wrapper';
// If it's the "yes" button
if ($(this).hasClass('yes')) {
// Slide the map wrapper down
$(map_wrapper_selector).slideDown('fast', function() {
// When the transition has finished:
// Get the map's intended center
var mapCenter = slt_cf_maps[map_container_id].map.getCenter();
// Trigger the map resize event to fill the wrapper
google.maps.event.trigger( slt_cf_maps[map_container_id].map, "resize" );
// Reset the map center with the new bounds
slt_cf_maps[map_container_id].map.setCenter(mapCenter);
});
}
// Otherwise, default to closing the map
else {
$(map_wrapper_selector).slideUp();
}
});
});