PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.6.7
VikBooking Hotel Booking Engine & PMS v1.6.7
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
vikbooking / admin / views / manageroom / tmpl / default_geocoding_info.php

default_geocoding_info.php in VikBooking Hotel Booking Engine & PMS 1.6.7, at admin/views/manageroom/tmpl/default_geocoding_info.php

1,714 lines 66.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage com_vikbooking
5 * @author Alessio Gaggii - e4j - Extensionsforjoomla.com
6 * @copyright Copyright (C) 2018 e4j - Extensionsforjoomla.com. All rights reserved.
7 * @license GNU General Public License version 2 or later; see LICENSE
8 * @link https://vikwp.com
9 */
10
11 defined('ABSPATH') or die('No script kiddies please!');
12
13 $vbo_app = VikBooking::getVboApplication();
14 $geo = VikBooking::getGeocodingInstance()->loadAssets();
15 $geo_supported = $geo->isSupported();
16 $rooms_params = count($this->row) ? json_decode($this->row['params'], true) : array();
17 $geo_import_from = $geo->getImportableConfigRooms((count($this->row) ? $this->row['id'] : 0));
18
19 // load colorpicker assets
20 JFactory::getDocument()->addStyleSheet(VBO_ADMIN_URI.'resources/js_upload/colorpicker.css');
21 JHtml::fetch('script', VBO_ADMIN_URI.'resources/js_upload/colorpicker.js');
22
23 // load lang vars for JS
24 JText::script('VBO_GEO_MARKERS_MULTI_ERRUNIT');
25 JText::script('VBODISTFEATURERUNIT');
26 JText::script('VBO_GEO_ADDRESS');
27 JText::script('VBO_GEO_CUSTOMIZE_MARKER');
28 JText::script('VBMAINPAYMENTSDEL');
29 JText::script('VBO_GEO_RMCONF_MARKER');
30 JText::script('VBO_WIDGETS_CONFRMELEM');
31 JText::script('VBO_GEO_HIDE_FROM_MAP');
32 JText::script('VBO_GEO_MAP_GOVERLAY');
33 JText::script('VBO_PLEASE_SELECT');
34 JText::script('VBO_GEO_IMPORT_FROM');
35 JText::script('VBO_GEO_IMPORT_CONF');
36 JText::script('VBO_GEO_FAILED_REASON');
37 JText::script('VBO_PLEASE_FILL_FIELDS');
38 ?>
39 <fieldset class="adminform">
40 <div class="vbo-params-wrap">
41 <legend class="adminlegend">
42 <span class="vbo-geo-legend-title"><?php VikBookingIcons::e('map-marked-alt'); ?> <?php echo JText::translate('VBO_GEO_INFO'); ?></span>
43 <?php
44 if ($geo_supported && count($geo_import_from)) {
45 ?>
46 <span class="vbo-geo-legend-import">
47 <select id="vbo-geo-importfrom" onchange="vboImportGeoConfig(this.value);">
48 <option></option>
49 <?php
50 foreach ($geo_import_from as $impfrom) {
51 ?>
52 <option value="<?php echo $impfrom['id']; ?>"><?php echo $impfrom['name']; ?></option>
53 <?php
54 }
55 ?>
56 </select>
57 </span>
58 <?php
59 }
60 ?>
61 </legend>
62 <div class="vbo-params-container">
63 <div class="vbo-param-container">
64 <div class="vbo-param-label"><?php echo JText::translate('VBO_ENABLE_GEOCODING'); ?></div>
65 <div class="vbo-param-setting">
66 <?php
67 $geo_enabled = (int)$geo->getRoomGeoParams($rooms_params, 'enabled', 0);
68 echo $vbo_app->printYesNoButtons('geo_enabled', JText::translate('VBYES'), JText::translate('VBNO'), $geo_enabled, 1, 0, 'vboToggleGeoParams();');
69 ?>
70 </div>
71 </div>
72 <?php
73 if (!$geo_supported) {
74 ?>
75 <div class="vbo-param-container vbo-geoinfo-param" style="<?php echo !$geo_enabled ? 'display: none;' : ''; ?>">
76 <div class="vbo-param-setting">
77 <p class="warn notice-noicon"><?php VikBookingIcons::e('exclamation-triangle'); ?> <?php echo JText::translate('VBO_GEO_UNSUPPORTED'); ?></p>
78 </div>
79 </div>
80 <?php
81 } else {
82 ?>
83 <div class="vbo-param-container vbo-geoinfo-param" style="display: none;">
84 <div class="vbo-param-label"><?php echo JText::translate('VBO_GEO_ADDRESS'); ?></div>
85 <div class="vbo-param-setting">
86 <input type="text" id="geo_address" value="<?php echo $geo->getRoomGeoParams($rooms_params, 'address', ''); ?>" />
87 <span class="vbo-param-setting-comment" id="geo_address_formatted"></span>
88 </div>
89 </div>
90 <div class="vbo-param-container vbo-geoinfo-param" style="display: none;">
91 <div class="vbo-param-label"><?php echo JText::translate('VBO_GEO_COORDS'); ?></div>
92 <div class="vbo-param-setting">
93 <span><?php echo JText::translate('VBO_GEO_COORDS_LAT'); ?></span>
94 <input type="number" id="geo_latitude" class="vbo-large-input-number" min="-90" max="90" step="any" value="<?php echo $geo->getRoomGeoParams($rooms_params, 'latitude', '43.7734385'); ?>" />
95 <span><?php echo JText::translate('VBO_GEO_COORDS_LNG'); ?></span>
96 <input type="number" id="geo_longitude" class="vbo-large-input-number" min="-180" max="180" step="any" value="<?php echo $geo->getRoomGeoParams($rooms_params, 'longitude', '11.2565501'); ?>" />
97 </div>
98 </div>
99 <div class="vbo-param-container vbo-geoinfo-param" style="display: none;">
100 <div class="vbo-param-label"><?php echo JText::translate('VBO_GEO_ZOOM'); ?></div>
101 <div class="vbo-param-setting">
102 <input type="number" id="geo_zoom" min="0" step="any" value="<?php echo (int)$geo->getRoomGeoParams($rooms_params, 'zoom', 3); ?>" />
103 </div>
104 </div>
105 <div class="vbo-param-container vbo-geoinfo-param" style="display: none;">
106 <div class="vbo-param-label"><?php echo JText::translate('VBO_GEO_MTYPE'); ?></div>
107 <div class="vbo-param-setting">
108 <?php
109 $geo_mtype = $geo->getRoomGeoParams($rooms_params, 'mtype', 'roadmap');
110 ?>
111 <select id="geo_mtype">
112 <option value="roadmap"<?php echo $geo_mtype == 'roadmap' ? ' selected="selected"' : ''; ?>><?php echo JText::translate('VBO_GEO_MTYPE_ROADMAP'); ?></option>
113 <option value="satellite"<?php echo $geo_mtype == 'satellite' ? ' selected="selected"' : ''; ?>><?php echo JText::translate('VBO_GEO_MTYPE_SATELLITE'); ?></option>
114 <option value="hybrid"<?php echo $geo_mtype == 'hybrid' ? ' selected="selected"' : ''; ?>><?php echo JText::translate('VBO_GEO_MTYPE_HYBRID'); ?></option>
115 <option value="terrain"<?php echo $geo_mtype == 'terrain' ? ' selected="selected"' : ''; ?>><?php echo JText::translate('VBO_GEO_MTYPE_TERRAIN'); ?></option>
116 </select>
117 </div>
118 </div>
119 <div class="vbo-param-container vbo-geoinfo-param" style="display: none;">
120 <div class="vbo-param-label"><?php echo JText::translate('VBO_GEO_MAP_HEIGHT'); ?></div>
121 <div class="vbo-param-setting">
122 <input type="number" id="geo_height" min="50" max="3500" step="5" value="<?php echo $geo->getRoomGeoParams($rooms_params, 'height', 300); ?>" /> px
123 </div>
124 </div>
125 <div class="vbo-param-container vbo-geoinfo-param" style="display: none;">
126 <div class="vbo-param-setting">
127 <div id="vbo-geo-map" style="width: 100%; height: <?php echo $geo->getRoomGeoParams($rooms_params, 'height', 300); ?>px;"></div>
128 <?php
129 // main room marker position
130 $main_marker_lat = $geo->getRoomGeoParams($rooms_params, 'marker_lat', '');
131 $main_marker_lng = $geo->getRoomGeoParams($rooms_params, 'marker_lng', '');
132 $main_marker_hide = $geo->getRoomGeoParams($rooms_params, 'marker_hide', '');
133 $main_marker_pos = null;
134 if (empty($main_marker_hide) && !empty($main_marker_lat) && !empty($main_marker_lng)) {
135 // prepare main marker (for base address) object for js
136 $main_marker_pos = new stdClass;
137 $main_marker_pos->lat = (float)$main_marker_lat;
138 $main_marker_pos->lng = (float)$main_marker_lng;
139 }
140 ?>
141 <input type="hidden" id="geo_marker_lat" value="<?php echo $main_marker_lat; ?>" />
142 <input type="hidden" id="geo_marker_lng" value="<?php echo $main_marker_lng; ?>" />
143 <input type="hidden" id="geo_marker_hide" value="<?php echo $main_marker_hide; ?>" />
144 </div>
145 </div>
146 <div class="vbo-param-container vbo-geoinfo-param" style="display: none;">
147 <div class="vbo-param-label">
148 <?php
149 echo $vbo_app->createPopover(array('title' => JText::translate('VBO_GEO_MARKERS_ONEMULTI'), 'content' => JText::translate('VBO_GEO_MARKERS_ONEMULTI_HELP'), 'icon_class' => VikBookingIcons::i('map-marker-alt')));
150 echo ' ' . JText::translate('VBO_GEO_MARKERS_ONEMULTI');
151 ?>
152 </div>
153 <div class="vbo-param-setting">
154 <?php
155 $geo_markers_multi = $geo->getRoomGeoParams($rooms_params, 'markers_multi', 0);
156 ?>
157 <select id="geo_markers_multi">
158 <option value="0"<?php echo $geo_markers_multi == 0 ? ' selected="selected"' : ''; ?>><?php echo JText::translate('VBO_GEO_MARKERS_ONE'); ?></option>
159 <option value="1"<?php echo $geo_markers_multi == 1 ? ' selected="selected"' : ''; ?>><?php echo JText::translate('VBO_GEO_MARKERS_MULTI'); ?></option>
160 </select>
161 </div>
162 </div>
163 <div class="vbo-param-container vbo-geoinfo-param" style="display: none;">
164 <div class="vbo-param-setting vbo-geoinfo-markers-wrap"></div>
165 </div>
166 <div class="vbo-param-container vbo-geoinfo-param" style="display: none;">
167 <div class="vbo-param-label">
168 <?php
169 echo $vbo_app->createPopover(array('title' => JText::translate('VBO_GEO_MAP_GOVERLAY'), 'content' => JText::translate('VBO_GEO_MAP_GOVERLAY_HELP'), 'icon_class' => VikBookingIcons::i('images')));
170 echo ' ' . JText::translate('VBO_GEO_MAP_GOVERLAY');
171 ?>
172 </div>
173 <div class="vbo-param-setting">
174 <?php
175 $goverlay_enabled = (int)$geo->getRoomGeoParams($rooms_params, 'goverlay', 0);
176 echo $vbo_app->printYesNoButtons('geo_goverlay', JText::translate('VBYES'), JText::translate('VBNO'), $goverlay_enabled, 1, 0, 'vboToggleGeoGroundOverlay();');
177 ?>
178 <button type="button" id="vbo-goverlay-edit" class="btn vbo-config-btn" style="<?php echo !$goverlay_enabled ? 'display: none;' : ''; ?>" onclick="vboToggleGeoGroundOverlay();"><?php VikBookingIcons::e('images'); ?> <?php echo JText::translate('VBMAINPAYMENTSEDIT'); ?></button>
179 </div>
180 </div>
181 <?php
182 }
183 ?>
184 </div>
185 </div>
186 </fieldset>
187
188 <script type="text/javascript">
189 function vboToggleGeoParams() {
190 if (jQuery('input[name="geo_enabled"]').is(':checked')) {
191 jQuery('.vbo-geoinfo-param').show();
192
193 // make a silent AJAX request only once to prepare the temporary record used to store the room geo information
194 var room_id = <?php echo count($this->row) ? $this->row['id'] : '0'; ?>;
195 if (room_id < 1) {
196 var call_method = 'initRoomGeoTransient';
197 jQuery.ajax({
198 type: "POST",
199 url: "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=geocoding_endpoint'); ?>",
200 data: {
201 tmpl: "component",
202 callback: call_method,
203 room_id: room_id
204 }
205 }).done(function(response) {
206 try {
207 var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
208 if (!obj_res.hasOwnProperty(call_method)) {
209 console.error('initRoomGeoTransient unexpected JSON response', obj_res);
210 } else {
211 // console.log(obj_res[call_method]);
212 }
213 } catch(err) {
214 console.error('initRoomGeoTransient could not parse JSON response', err, response);
215 }
216 }).fail(function(err) {
217 console.error('initRoomGeoTransient request failed', err);
218 });
219 }
220 //
221 } else {
222 jQuery('.vbo-geoinfo-param').hide();
223 }
224 }
225 </script>
226 <?php
227 if ($geo_supported) {
228 $current_units_pos = $geo->getRoomGeoParams($rooms_params, 'units_pos');
229 $current_units_pos = is_object($current_units_pos) ? $current_units_pos : (new stdClass);
230 $current_goverlay = null;
231 if ((int)$geo->getRoomGeoParams($rooms_params, 'goverlay', 0)) {
232 $current_overlay_img = $geo->getRoomGeoParams($rooms_params, 'overlay_img', '');
233 $current_overlay_south = $geo->getRoomGeoParams($rooms_params, 'overlay_south');
234 $current_overlay_west = $geo->getRoomGeoParams($rooms_params, 'overlay_west');
235 $current_overlay_north = $geo->getRoomGeoParams($rooms_params, 'overlay_north');
236 $current_overlay_east = $geo->getRoomGeoParams($rooms_params, 'overlay_east');
237 if (!empty($current_overlay_img) && !empty($current_overlay_south)) {
238 // ground overlay is available
239 $current_goverlay = new stdClass;
240 $current_goverlay->url = $current_overlay_img;
241 $current_goverlay->south = (float)$current_overlay_south;
242 $current_goverlay->west = (float)$current_overlay_west;
243 $current_goverlay->north = (float)$current_overlay_north;
244 $current_goverlay->east = (float)$current_overlay_east;
245 }
246 }
247 ?>
248 <script type="text/javascript">
249 /**
250 * Define global scope vars
251 */
252 var vbo_geomap = null,
253 vbo_geomap_saving = false,
254 vbo_geocoder = null,
255 vbo_geomarker_room = null,
256 vbo_geomarker_room_pos = <?php echo is_object($main_marker_pos) ? json_encode($main_marker_pos) : 'null'; ?>,
257 vbo_info_marker_room = null,
258 vbo_geomarker_units = {},
259 vbo_geomarker_units_pos = <?php echo json_encode($current_units_pos); ?>,
260 vbo_info_markers = {},
261 vbo_current_marker_index = null,
262 vbo_icn_marker_in = '<?php echo VikBookingIcons::i('map-marked-alt', 'vbo-geo-marker-icn-in'); ?>',
263 vbo_icn_marker_out = '<?php echo VikBookingIcons::i('map', 'vbo-geo-marker-icn-out'); ?>',
264 vbo_marker_base_uri = '<?php echo JUri::root(); ?>',
265 vbo_doing_ground_overlay = false,
266 vbo_ground_overlay = null,
267 vbo_dbground_overlay = <?php echo is_object($current_goverlay) ? json_encode($current_goverlay) : 'null'; ?>;
268
269 var vbo_modal_geomap_on = false;
270
271 /**
272 * Delay saving button if saving the geomap
273 */
274 Joomla.submitbutton = function(task) {
275 if (vbo_geomap_saving && (task.indexOf('updateroom') >= 0 || task.indexOf('createroom') >= 0)) {
276 console.log('Delay saving to allow geomap saving');
277 setTimeout(function() {
278 Joomla.submitform(task, document.adminForm);
279 }, 750);
280 } else {
281 Joomla.submitform(task, document.adminForm);
282 }
283 }
284
285 /**
286 * Shows the modal window
287 */
288 function vboOpenModalGeoMap() {
289 jQuery('.vbo-modal-overlay-block-geomap').show();
290 vbo_modal_geomap_on = true;
291 }
292
293 /**
294 * Hides the modal window
295 */
296 function hideVboModalGeoMap() {
297 if (vbo_modal_geomap_on === true) {
298 jQuery(".vbo-modal-overlay-block-geomap").fadeOut(400, function () {
299 jQuery(".vbo-modal-overlay-content-geomap").show();
300 });
301 // turn flag off
302 vbo_modal_geomap_on = false;
303 }
304 if (vbo_doing_ground_overlay === true) {
305 if (vbo_ground_overlay === null) {
306 // no overlay set, make sure to deselect the toggle
307 jQuery('input[name="geo_goverlay"]').prop('checked', false);
308 }
309 // turn flag off
310 vbo_doing_ground_overlay = false;
311 }
312 }
313
314 /**
315 * Converts an RGB (or RGBA) color to hexadecimal
316 */
317 function vboRgb2Hex(rgb) {
318 var rgb_match = rgb.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([0-9.]+))?\)$/);
319 if (!rgb_match) {
320 return rgb;
321 }
322 return "#" + vboHex(rgb_match[1]) + vboHex(rgb_match[2]) + vboHex(rgb_match[3]);
323 }
324
325 /**
326 * Composes RGB (or RGBA) color values to hexadecimal
327 */
328 function vboHex(x) {
329 var vboHexDigits = new Array ("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f");
330 return isNaN(x) ? "00" : vboHexDigits[(x - x % 16) / 16] + vboHexDigits[x % 16];
331 }
332
333 /**
334 * Debounce technique to group a flurry of events into one single event.
335 * This is useful for listening to the key up event of the address.
336 */
337 function vboDebounceEvent(func, wait, immediate) {
338 var timeout;
339 return function() {
340 var context = this, args = arguments;
341 var later = function() {
342 timeout = null;
343 if (!immediate) func.apply(context, args);
344 };
345 var callNow = immediate && !timeout;
346 clearTimeout(timeout);
347 timeout = setTimeout(later, wait);
348 if (callNow) {
349 func.apply(context, args);
350 }
351 }
352 }
353
354 /**
355 * Fires when the document is ready. Renders the entire map.
356 */
357 function vboInitGeoMap() {
358 // default map options
359 var def_map_options = {
360 center: new google.maps.LatLng(jQuery('#geo_latitude').val(), jQuery('#geo_longitude').val()),
361 zoom: parseFloat(jQuery('#geo_zoom').val()),
362 mapTypeId: jQuery('#geo_mtype').val()
363 };
364 // initialize Map
365 vbo_geomap = new google.maps.Map(document.getElementById('vbo-geo-map'), def_map_options);
366 // add listeners to map
367 vbo_geomap.addListener('bounds_changed', function() {
368 // update zoom
369 jQuery('#geo_zoom').val(vbo_geomap.getZoom());
370 // update center coordinates
371 var center_bounds = vbo_geomap.getBounds().getCenter();
372 jQuery('#geo_latitude').val(center_bounds.lat());
373 jQuery('#geo_longitude').val(center_bounds.lng());
374 // trigger the geo-saving event
375 document.dispatchEvent(new Event('vbo-room-geosaving'));
376 });
377 vbo_geomap.addListener('maptypeid_changed', function() {
378 // this will return the constant of the mapTypeId
379 var maptypeid = vbo_geomap.getMapTypeId();
380 jQuery('#geo_mtype').val((maptypeid + '').toLowerCase());
381 // trigger the geo-saving event
382 document.dispatchEvent(new Event('vbo-room-geosaving'));
383 });
384 vbo_geomap.addListener('click', function(e) {
385 // handle the map click by passing the position
386 vboGeoMapClickedPos(e.latLng);
387 });
388 // initialize Geocoder
389 vbo_geocoder = new google.maps.Geocoder();
390 // set current default marker for main room
391 if (vbo_geomarker_room_pos !== null) {
392 // create infowindow
393 vbo_info_marker_room = new google.maps.InfoWindow({
394 content: vboGenerateMainInfoMarkerContent(),
395 disableAutoPan: true
396 });
397 // add map marker for base room-type
398 vbo_geomarker_room = new google.maps.Marker({
399 draggable: true,
400 map: vbo_geomap,
401 position: {
402 lat: parseFloat(vbo_geomarker_room_pos.lat),
403 lng: parseFloat(vbo_geomarker_room_pos.lng)
404 },
405 title: jQuery('input[name="cname"]').val()
406 });
407 // add listener to marker
408 vbo_geomarker_room.addListener('dragend', function() {
409 // update lat and lng of main room's marker
410 var current_lat = vbo_geomarker_room.getPosition().lat();
411 var current_lng = vbo_geomarker_room.getPosition().lng();
412 jQuery('#geo_marker_lat').val(current_lat);
413 jQuery('#geo_marker_lng').val(current_lng);
414 // update the same information in the marker position
415 if (vbo_geomarker_room_pos !== null) {
416 vbo_geomarker_room_pos['lat'] = current_lat;
417 vbo_geomarker_room_pos['lng'] = current_lng;
418 }
419 // trigger the geo-saving event
420 document.dispatchEvent(new Event('vbo-room-geosaving'));
421 });
422 vbo_geomarker_room.addListener('click', function() {
423 // close any other open infowindow first
424 for (var m in vbo_info_markers) {
425 if (!vbo_info_markers.hasOwnProperty(m)) {
426 continue;
427 }
428 vbo_info_markers[m].close();
429 }
430 vbo_info_marker_room.open(vbo_geomap, vbo_geomarker_room);
431 });
432
433 }
434 // populate current markers, if any
435 vboPopulateMapMarkers();
436 // populate ground overlay image, if set
437 if (vbo_dbground_overlay !== null) {
438 // compose LatLngBounds object
439 var overlay_bounds = new google.maps.LatLngBounds(
440 new google.maps.LatLng(parseFloat(vbo_dbground_overlay.south), parseFloat(vbo_dbground_overlay.west)),
441 new google.maps.LatLng(parseFloat(vbo_dbground_overlay.north), parseFloat(vbo_dbground_overlay.east))
442 );
443 // update ground overlay object
444 vbo_ground_overlay = new google.maps.GroundOverlay(vbo_dbground_overlay.url, overlay_bounds);
445 // set the overlay to the map
446 vbo_ground_overlay.setMap(vbo_geomap);
447 }
448 }
449
450 /**
451 * Simple way for centering the map, but this won't fit all marker bounds.
452 */
453 function vboSetGeoMapCenter(lat, lng) {
454 if (vbo_geomap === null) {
455 console.error('map is null');
456 return false;
457 }
458 if (isNaN(lat) || isNaN(lng)) {
459 console.error('latitude and longitude must be numbers', lat, lng);
460 return false;
461 }
462 vbo_geomap.setCenter(new google.maps.LatLng(lat, lng));
463 }
464
465 /**
466 * Gets the position of all markers to extend the bounds,
467 * and then sets the zoom and bounds to fit them all.
468 */
469 function vboGeoMapCenterBounds() {
470 if (vbo_geomap === null) {
471 console.error('map is null');
472 return false;
473 }
474 // set map center and zoom automatically
475 var latlngbounds = new google.maps.LatLngBounds();
476 // check if main address marker is in the map
477 if (vbo_geomarker_room !== null) {
478 latlngbounds.extend(vbo_geomarker_room.getPosition());
479 }
480 // parse all room-units markers
481 for (var i in vbo_geomarker_units) {
482 if (!vbo_geomarker_units.hasOwnProperty(i)) {
483 continue;
484 }
485 latlngbounds.extend(vbo_geomarker_units[i].getPosition());
486 }
487 // apply calculated center and bounds
488 vbo_geomap.setCenter(latlngbounds.getCenter());
489 vbo_geomap.fitBounds(latlngbounds);
490 }
491
492 /**
493 * Fires when typing an address to geocode it within the map.
494 */
495 function vboAddressGeocoding() {
496 // reset formatted address
497 jQuery('#geo_address_formatted').text('');
498
499 var address = jQuery('#geo_address').val();
500 if (!address.length) {
501 return;
502 }
503 vbo_geocoder.geocode({'address': address}, function(results, status) {
504 if (status == 'OK') {
505 if (results.length > 1) {
506 console.log('multiple address results returned', results);
507 }
508 // populate formatted address
509 if (results[0].hasOwnProperty('formatted_address')) {
510 jQuery('#geo_address_formatted').text(results[0].formatted_address);
511 }
512 // update coordinates
513 jQuery('#geo_latitude').val(results[0].geometry.location.lat());
514 jQuery('#geo_longitude').val(results[0].geometry.location.lng());
515 // remove any previously added marker for main room
516 if (vbo_geomarker_room !== null) {
517 vbo_geomarker_room.setMap(null);
518 }
519 // create infowindow
520 vbo_info_marker_room = new google.maps.InfoWindow({
521 content: vboGenerateMainInfoMarkerContent(),
522 disableAutoPan: true
523 });
524 // add map marker for base room-type
525 vbo_geomarker_room = new google.maps.Marker({
526 draggable: true,
527 map: vbo_geomap,
528 position: results[0].geometry.location,
529 title: jQuery('input[name="cname"]').val()
530 });
531 // set new coords for marker
532 jQuery('#geo_marker_lat').val(results[0].geometry.location.lat());
533 jQuery('#geo_marker_lng').val(results[0].geometry.location.lng());
534 jQuery('#geo_marker_hide').val('');
535 // add listener to marker
536 vbo_geomarker_room.addListener('dragend', function() {
537 // update lat and lng of main room's marker
538 var current_lat = vbo_geomarker_room.getPosition().lat();
539 var current_lng = vbo_geomarker_room.getPosition().lng();
540 jQuery('#geo_marker_lat').val(current_lat);
541 jQuery('#geo_marker_lng').val(current_lng);
542 // update the same information in the marker position
543 if (vbo_geomarker_room_pos === null) {
544 vbo_geomarker_room_pos = {};
545 }
546 vbo_geomarker_room_pos['lat'] = current_lat;
547 vbo_geomarker_room_pos['lng'] = current_lng;
548 // trigger the geo-saving event
549 document.dispatchEvent(new Event('vbo-room-geosaving'));
550 });
551 vbo_geomarker_room.addListener('click', function() {
552 // close any other open infowindow first
553 for (var m in vbo_info_markers) {
554 if (!vbo_info_markers.hasOwnProperty(m)) {
555 continue;
556 }
557 vbo_info_markers[m].close();
558 }
559 vbo_info_marker_room.open(vbo_geomap, vbo_geomarker_room);
560 });
561 // set map center and zoom automatically
562 vboGeoMapCenterBounds();
563 } else {
564 alert(Joomla.JText._('VBO_GEO_FAILED_REASON') + ' ' + status);
565 }
566 });
567 }
568
569 /**
570 * Given all the current positions, adds the current markers to the map and register the events.
571 */
572 function vboPopulateMapMarkers() {
573 // always reset markers pool and remove them from map
574 for (var i in vbo_geomarker_units) {
575 if (!vbo_geomarker_units.hasOwnProperty(i)) {
576 continue;
577 }
578 // remove current marker from map
579 vbo_geomarker_units[i].setMap(null);
580 }
581 // reset vars
582 vbo_geomarker_units = {};
583 vbo_info_markers = {};
584 // empty markers wrap
585 jQuery('.vbo-geoinfo-markers-wrap').html('');
586 // calculate limits
587 var multi_markers = jQuery('#geo_markers_multi').val();
588 var room_units = jQuery('#room_units').val();
589 var tot_markers = multi_markers > 0 && room_units > 1 ? room_units : 1;
590 tot_markers = parseInt(tot_markers);
591 // iterate through markers to add and display
592 for (var i = 1; i <= tot_markers; i++) {
593 var marker_options = null;
594 var marker_title = Joomla.JText._('VBODISTFEATURERUNIT') + (i + '');
595 if (tot_markers === 1 && jQuery('input[name="cname"]').val().length) {
596 marker_title = jQuery('input[name="cname"]').val();
597 }
598 if (vbo_geomarker_units_pos.hasOwnProperty(i)) {
599 // marker index saved
600 marker_options = {
601 draggable: true,
602 map: vbo_geomap,
603 position: {
604 lat: parseFloat(vbo_geomarker_units_pos[i].lat),
605 lng: parseFloat(vbo_geomarker_units_pos[i].lng)
606 },
607 title: marker_title
608 };
609 // set custom unit property
610 marker_options['vbo_unit'] = i;
611 // check if we know a custom icon for this marker
612 if (vbo_geomarker_units_pos[i].hasOwnProperty('icon')) {
613 marker_options['icon'] = vbo_geomarker_units_pos[i]['icon'];
614 }
615 // create marker infowindow
616 var vbo_info_marker_cont = vboGenerateInfoMarkerContent(i, marker_title);
617 var vbo_info_marker = new google.maps.InfoWindow({
618 content: vbo_info_marker_cont,
619 disableAutoPan: true
620 });
621 // add unit marker to map
622 var vbo_geomarker_runit = new google.maps.Marker(marker_options);
623 // add listener to marker
624 vbo_geomarker_runit.addListener('dragend', function(e) {
625 // update lat and lng of room unit marker
626 var current_lat = this.getPosition().lat();
627 var current_lng = this.getPosition().lng();
628 if (vbo_geomarker_units_pos.hasOwnProperty(this['vbo_unit'])) {
629 vbo_geomarker_units_pos[this['vbo_unit']]['lat'] = current_lat;
630 vbo_geomarker_units_pos[this['vbo_unit']]['lng'] = current_lng;
631 }
632 // trigger the geo-saving event
633 document.dispatchEvent(new Event('vbo-room-geosaving'));
634 });
635 vbo_geomarker_runit.addListener('click', function() {
636 if (this['vbo_unit'] && vbo_info_markers.hasOwnProperty(this['vbo_unit'])) {
637 // close any other open infowindow first
638 for (var m in vbo_info_markers) {
639 if (!vbo_info_markers.hasOwnProperty(m) || m == this['vbo_unit']) {
640 continue;
641 }
642 vbo_info_markers[m].close();
643 }
644 if (vbo_geomarker_room !== null && vbo_info_marker_room !== null) {
645 // close address marker infowindow
646 vbo_info_marker_room.close();
647 }
648 vbo_info_markers[this['vbo_unit']].open(vbo_geomap, this);
649 } else {
650 console.error('info marker not found', this);
651 }
652 });
653 // register marker to pool
654 vbo_geomarker_units[i] = vbo_geomarker_runit;
655 // register info window
656 vbo_info_markers[i] = vbo_info_marker;
657 }
658 // build marker settings GUI
659 var marker_setting_wrap = '';
660 marker_setting_wrap += '<div class="vbo-geoinfo-marker-cont ' + (marker_options === null ? 'vbo-geoinfo-marker-out' : 'vbo-geoinfo-marker-in') + '" data-markerindex="' + i + '">';
661 marker_setting_wrap += ' <div class="vbo-geoinfo-marker-label">' + marker_title + '</div>';
662 marker_setting_wrap += ' <div class="vbo-geoinfo-marker-cmd">';
663 var marker_btn_icn = '';
664 if (marker_options === null) {
665 marker_btn_icn = '<i class="' + vbo_icn_marker_out + '"></i>';
666 } else {
667 marker_btn_icn = '<i class="' + vbo_icn_marker_in + '"></i>';
668 }
669 marker_setting_wrap += ' <button type="button" class="btn btn-small btn-secondary vbo-geomarker-status" onclick="vboManageRoomMarker(' + i + ');">' + marker_btn_icn + '</button>';
670 marker_setting_wrap += ' </div>';
671 marker_setting_wrap += '</div>';
672 // append marker settings
673 jQuery('.vbo-geoinfo-markers-wrap').append(marker_setting_wrap);
674 }
675 }
676
677 /**
678 * Adds a new marker to the map, or opens its info window if the marker index exists already.
679 */
680 function vboManageRoomMarker(index, position) {
681 if (!index || isNaN(index)) {
682 console.error('vboManageRoomMarker invalid argument', index);
683 return false;
684 }
685 if (vbo_geomap === null) {
686 console.error('map is empty');
687 return false;
688 }
689 if (vbo_geomarker_units.hasOwnProperty(index)) {
690 // close any other open infowindow first
691 for (var m in vbo_info_markers) {
692 if (!vbo_info_markers.hasOwnProperty(m) || m == index) {
693 continue;
694 }
695 vbo_info_markers[m].close();
696 }
697 if (vbo_geomarker_room !== null && vbo_info_marker_room !== null) {
698 // close address marker infowindow
699 vbo_info_marker_room.close();
700 }
701 // marker exists for this room-unit, open its infowindow
702 vbo_info_markers[index].open(vbo_geomap, vbo_geomarker_units[index]);
703 } else {
704 // marker does not exist, add it to map
705 var map_center = vbo_geomap.getCenter();
706 if (!map_center) {
707 console.error('Map center or bounds have not been set');
708 return false;
709 }
710 if (!position) {
711 // calculate new random position from current center and zoom level
712 var center_lat = map_center.lat();
713 var decims_lat = center_lat - parseInt(center_lat);
714 var center_lng = map_center.lng();
715 var decims_lng = center_lng - parseInt(center_lng);
716 var current_zoom = vbo_geomap.getZoom();
717 var increase = ((current_zoom + 1) * 2) / 100000;
718 decims_lat += increase;
719 decims_lng += increase;
720 position = {
721 lat: (parseInt(center_lat) + decims_lat),
722 lng: (parseInt(center_lng) + decims_lng)
723 }
724 }
725 // create marker
726 var marker_options = {
727 draggable: true,
728 map: vbo_geomap,
729 position: position,
730 title: Joomla.JText._('VBODISTFEATURERUNIT') + (index + '')
731 };
732 // set custom unit property
733 marker_options['vbo_unit'] = index;
734 // create marker infowindow
735 var vbo_info_marker_cont = vboGenerateInfoMarkerContent(index, null);
736 var vbo_info_marker = new google.maps.InfoWindow({
737 content: vbo_info_marker_cont,
738 disableAutoPan: true
739 });
740 // add unit marker to map
741 var vbo_geomarker_runit = new google.maps.Marker(marker_options);
742 // add listener to marker
743 vbo_geomarker_runit.addListener('dragend', function(e) {
744 // update lat and lng of room unit marker
745 var current_lat = this.getPosition().lat();
746 var current_lng = this.getPosition().lng();
747 if (vbo_geomarker_units_pos.hasOwnProperty(this['vbo_unit'])) {
748 vbo_geomarker_units_pos[this['vbo_unit']]['lat'] = current_lat;
749 vbo_geomarker_units_pos[this['vbo_unit']]['lng'] = current_lng;
750 }
751 // trigger the geo-saving event
752 document.dispatchEvent(new Event('vbo-room-geosaving'));
753 });
754 vbo_geomarker_runit.addListener('click', function() {
755 if (this['vbo_unit'] && vbo_info_markers.hasOwnProperty(this['vbo_unit'])) {
756 // close any other open infowindow first
757 for (var m in vbo_info_markers) {
758 if (!vbo_info_markers.hasOwnProperty(m) || m == this['vbo_unit']) {
759 continue;
760 }
761 vbo_info_markers[m].close();
762 }
763 if (vbo_geomarker_room !== null && vbo_info_marker_room !== null) {
764 // close address marker infowindow
765 vbo_info_marker_room.close();
766 }
767 vbo_info_markers[this['vbo_unit']].open(vbo_geomap, this);
768 } else {
769 console.error('info marker not found', this);
770 }
771 });
772 // register marker to pool
773 vbo_geomarker_units[index] = vbo_geomarker_runit;
774 // register marker position
775 if (typeof position.lat == 'function') {
776 // position may be a LatLng object, convert it to number properties
777 var prop_position = {
778 lat: position.lat(),
779 lng: position.lng()
780 };
781 position = prop_position;
782 }
783 vbo_geomarker_units_pos[index] = position;
784 // register info window
785 vbo_info_markers[index] = vbo_info_marker;
786 // center map to fit all markers
787 vboGeoMapCenterBounds();
788 // update marker settings status
789 var settings_btn = jQuery('.vbo-geoinfo-marker-cont[data-markerindex="' + index + '"]').find('.vbo-geoinfo-marker-cmd').find('.vbo-geomarker-status');
790 if (settings_btn && settings_btn.length) {
791 settings_btn.find('i').removeClass().addClass(vbo_icn_marker_in);
792 jQuery('.vbo-geoinfo-marker-cont[data-markerindex="' + index + '"]').removeClass('vbo-geoinfo-marker-out').addClass('vbo-geoinfo-marker-in');
793 }
794 // trigger the geo-saving event
795 document.dispatchEvent(new Event('vbo-room-geosaving'));
796 }
797 }
798
799 /**
800 * Prompts the confirmation for removing a room-unit marker from the map
801 */
802 function vboRemoveMarker(index) {
803 if (confirm(Joomla.JText._('VBO_GEO_RMCONF_MARKER'))) {
804 // remove marker from map
805 vbo_geomarker_units[index].setMap(null);
806 // remove object properties
807 delete vbo_geomarker_units[index];
808 delete vbo_geomarker_units_pos[index];
809 delete vbo_info_markers[index];
810 // update marker settings status
811 var settings_btn = jQuery('.vbo-geoinfo-marker-cont[data-markerindex="' + index + '"]').find('.vbo-geoinfo-marker-cmd').find('.vbo-geomarker-status');
812 if (settings_btn && settings_btn.length) {
813 settings_btn.find('i').removeClass().addClass(vbo_icn_marker_out);
814 jQuery('.vbo-geoinfo-marker-cont[data-markerindex="' + index + '"]').removeClass('vbo-geoinfo-marker-in').addClass('vbo-geoinfo-marker-out');
815 }
816 // trigger the geo-saving event
817 document.dispatchEvent(new Event('vbo-room-geosaving'));
818 }
819 }
820
821 /**
822 * Prompts the confirmation for removing the address marker from the map
823 */
824 function vboRemoveAddressMarker() {
825 if (vbo_geomarker_room === null) {
826 return false;
827 }
828 if (confirm(Joomla.JText._('VBO_GEO_RMCONF_MARKER'))) {
829 // remove marker from map
830 vbo_geomarker_room.setMap(null);
831 // unset object properties
832 vbo_geomarker_room = null;
833 vbo_geomarker_room_pos = null;
834 // set main marker for hiding
835 jQuery('#geo_marker_hide').val('1');
836 // trigger the geo-saving event
837 document.dispatchEvent(new Event('vbo-room-geosaving'));
838 }
839 }
840
841 /**
842 * Opens the modal to customize the currently selected map marker
843 */
844 function vboCustomizeMarker(index) {
845 if (!vbo_geomarker_units.hasOwnProperty(index)) {
846 console.error('marker not found from given index', index, vbo_geomarker_units);
847 return false;
848 }
849 // update current marker index
850 vbo_current_marker_index = index;
851 // set proper modal title
852 jQuery('#vbo-modal-geomap-title').html('<?php VikBookingIcons::e('map-marker-alt'); ?> ' + Joomla.JText._('VBO_GEO_CUSTOMIZE_MARKER'));
853 // open modal
854 jQuery('.vbo-cust-geo-overlay-wrapper').hide();
855 jQuery('.vbo-cust-geo-marker-wrapper').show();
856 vboOpenModalGeoMap();
857 // populate current values of the modal depending on the current marker icon type
858 var current_icon = vbo_geomarker_units[index].getIcon();
859 if (!current_icon) {
860 // default icon of Google Maps (null or undefined)
861 jQuery('#vbo-geo-marker-icntype').val('google').trigger('change');
862 } else if (current_icon.hasOwnProperty('path')) {
863 // SVG path symbol
864 jQuery('#vbo-geo-marker-icntype').val('symbol').trigger('change');
865 // deselect all SVG icons
866 jQuery('.vbo-cust-geo-marker-svg').attr('data-markerapply', '0');
867 // select current SVG icon by using the custom property "vbo_icon_id"
868 if (current_icon.hasOwnProperty('vbo_icon_id')) {
869 jQuery('.vbo-cust-geo-marker-svg[data-markerid="' + current_icon['vbo_icon_id'] + '"]').trigger('click');
870 }
871 } else if (current_icon.hasOwnProperty('url')) {
872 // icon URL
873 jQuery('#vbo-geo-marker-icntype').val('icon').trigger('change');
874 // set width and height, if any
875 var icon_width = null,
876 icon_height = null;
877 if (current_icon.hasOwnProperty('scaledSize') && current_icon['scaledSize'].hasOwnProperty('width')) {
878 icon_width = current_icon['scaledSize']['width'];
879 icon_height = current_icon['scaledSize']['height'];
880 } else if (current_icon.hasOwnProperty('size') && current_icon['size'].hasOwnProperty('width')) {
881 icon_width = current_icon['size']['width'];
882 icon_height = current_icon['size']['height'];
883 }
884 if (icon_width && icon_height) {
885 jQuery('#vbo-geo-marker-icon-width').val(icon_width);
886 jQuery('#vbo-geo-marker-icon-height').val(icon_height);
887 }
888 // try to populate the input value of the media manager
889 jQuery('input[name="marker_icon_img"]').val(current_icon['url'].replace(vbo_marker_base_uri, ''));
890 // try to set the current image, if any (this changes from J to WP)
891 if (jQuery('.image-preview-wrapper').length) {
892 jQuery('.vbo-cust-geo-marker-wrapper').find('.image-preview-wrapper').html('<img src="' + current_icon['url'] + '" />').show();
893 }
894 }
895 // populate default values
896 if (current_icon && current_icon.hasOwnProperty('fillColor') && current_icon['fillColor'].length) {
897 jQuery('#vbo-geo-marker-fillcolor').val(current_icon['fillColor']);
898 jQuery('.vbo-inspector-colorpicker').css('backgroundColor', current_icon['fillColor']);
899 }
900 if (current_icon && current_icon.hasOwnProperty('fillOpacity') && current_icon['fillOpacity'] >= 0) {
901 jQuery('#vbo-geo-marker-opacity').val(current_icon['fillOpacity']);
902 }
903 }
904
905 /**
906 * Triggers when changing the type of icon for the marker
907 */
908 function vboCustomizeMarkerChangeIconType(type) {
909 // always hide all conditional fields
910 jQuery('.vbo-cust-geo-marker-bottom').hide();
911 if (jQuery('.vbo-cust-geo-marker-bottom[data-geomarker="' + type + '"]').length) {
912 // show requested type
913 jQuery('.vbo-cust-geo-marker-bottom[data-geomarker="' + type + '"]').show();
914 if (type == 'icon') {
915 // lower the z-index of our modal to allow the media-manager modal to be displayed on top
916 jQuery('.vbo-modal-overlay-block-geomap').addClass('vbo-modal-overlay-block-geomap-lowerzindex');
917 } else {
918 // restore the original z-index of our modal
919 jQuery('.vbo-modal-overlay-block-geomap').removeClass('vbo-modal-overlay-block-geomap-lowerzindex');
920 }
921 }
922 }
923
924 /**
925 * Fires when clicking on an SVG path symbol
926 */
927 function vboCustomizeMarkerSelectSymbol(elem) {
928 elem = jQuery(elem);
929 jQuery('.vbo-cust-geo-marker-svg').attr('data-markerapply', '0');
930 elem.attr('data-markerapply', '1');
931 if (elem.hasClass('vbo-cust-geo-marker-svg-addnew')) {
932 elem.hide();
933 jQuery('.vbo-cust-geo-marker-svg-newfield').show();
934 // hide all regular customization fields
935 jQuery('.vbo-geo-marker-param-container').not('.vbo-cust-geo-marker-svg-newfield').hide();
936 } else {
937 jQuery('.vbo-cust-geo-marker-svg-addnew').show();
938 jQuery('.vbo-cust-geo-marker-svg-newfield').hide();
939 // restore all regular customization fields
940 jQuery('.vbo-geo-marker-param-container').not('.vbo-cust-geo-marker-svg-newfield').show();
941 // populate default styling from selected symbol
942 var current_fill = elem.find('svg').css('fill');
943 var current_opacity = elem.find('svg').css('opacity');
944 if (current_fill && current_fill.length) {
945 jQuery('.vbo-inspector-colorpicker').css('backgroundColor', current_fill);
946 if (current_fill.indexOf('rgb') >= 0) {
947 current_fill = vboRgb2Hex(current_fill);
948 }
949 jQuery('#vbo-geo-marker-fillcolor').val(current_fill);
950 }
951 if (current_opacity && current_opacity > 0) {
952 jQuery('#vbo-geo-marker-opacity').val(current_opacity);
953 }
954 }
955 jQuery('.vbo-cust-geo-marker-svg-adjust').show();
956 }
957
958 /**
959 * Fires on the keyup event of the textarea for the SVG path
960 */
961 function vboCustomizeMarkerSanitizeCustomSymbol() {
962 var cur_path = jQuery('#vbo-newsvg-path').val();
963 if (!cur_path.length) {
964 return;
965 }
966 // check if we got a full path tag with the "d" attribute
967 if ((/[^i]d="(.+)"/i).test(cur_path)) {
968 // grab only what's inside the path attribute
969 var matches = cur_path.match(/[^i]d="(.+)"/i);
970 // replace the value with just the content of the path attribute
971 jQuery('#vbo-newsvg-path').val(matches[1]);
972 return;
973 }
974 // always replace invalid characters that may break the content of the SVG
975 jQuery('#vbo-newsvg-path').val(cur_path.replace(/<|=|"|\/|>|\?/gi, ''));
976 return;
977 }
978
979 /**
980 * Fires when adding a new custom SVG symbol path
981 */
982 function vboCustomizeMarkerAddCustomSymbol() {
983 var cur_name = jQuery('#vbo-newsvg-name').val();
984 var cur_path = jQuery('#vbo-newsvg-path').val();
985 if (!cur_name.length || !cur_path.length) {
986 alert(Joomla.JText._('VBO_PLEASE_FILL_FIELDS'));
987 return false;
988 }
989 // compose ID for custom SVG
990 var now = new Date;
991 var svgid = now.getTime();
992 // compose new SVG element
993 var svgelem = '';
994 svgelem += '<div class="vbo-cust-geo-marker-svg" data-markerapply="0" data-markerid="' + svgid + '" data-markergroup="custom" onclick="vboCustomizeMarkerSelectSymbol(this);">';
995 svgelem += ' <div class="vbo-cust-geo-marker-svg-name">';
996 svgelem += ' <span>' + cur_name + '</span>';
997 svgelem += ' </div>';
998 svgelem += ' <div class="vbo-cust-geo-marker-svg-icon">';
999 svgelem += ' <svg>';
1000 svgelem += ' <path d="' + cur_path + '" />';
1001 svgelem += ' </svg>';
1002 svgelem += ' </div>';
1003 svgelem += '</div>';
1004 // deselect all icons
1005 jQuery('.vbo-cust-geo-marker-svg').attr('data-markerapply', '0');
1006 // unset and hide fields for adding new custom SVG
1007 jQuery('.vbo-cust-geo-marker-svg-newfield, .vbo-cust-geo-marker-svg-adjust').hide();
1008 jQuery('#vbo-newsvg-name, #vbo-newsvg-path').val('');
1009 // append new SVG element
1010 jQuery(svgelem).insertBefore('.vbo-cust-geo-marker-svg-addnew');
1011 // display again the add new button, but only one icon can be saved
1012 jQuery('.vbo-cust-geo-marker-svg-addnew').show();
1013 }
1014
1015 /**
1016 * Cancels the action of creating a custom symbol
1017 */
1018 function vboCustomizeMarkerCancelCustomSymbol() {
1019 // unset and hide fields for adding new custom SVG
1020 jQuery('.vbo-cust-geo-marker-svg-newfield, .vbo-cust-geo-marker-svg-adjust').hide();
1021 jQuery('#vbo-newsvg-name, #vbo-newsvg-path').val('');
1022 // restore add new button and deselect all choices
1023 jQuery('.vbo-cust-geo-marker-svg-addnew').show();
1024 jQuery('.vbo-cust-geo-marker-svg').attr('data-markerapply', '0');
1025 }
1026
1027 /**
1028 * Applies the selected changes to the current map marker
1029 */
1030 function vboCustomizeMarkerApply() {
1031 if (!vbo_current_marker_index || !vbo_geomarker_units.hasOwnProperty(vbo_current_marker_index)) {
1032 console.error('no active map marker found', vbo_current_marker_index, vbo_geomarker_units);
1033 return false;
1034 }
1035 // get icon type
1036 var icntype = jQuery('#vbo-geo-marker-icntype').val();
1037 if (!icntype.length || icntype == 'google') {
1038 // set default icon of Google Maps (by passing null)
1039 vbo_geomarker_units[vbo_current_marker_index].setIcon(null);
1040 // update icon in global object
1041 if (vbo_geomarker_units_pos !== null && vbo_geomarker_units_pos.hasOwnProperty(vbo_current_marker_index)) {
1042 delete vbo_geomarker_units_pos[vbo_current_marker_index]['icon'];
1043 }
1044 } else if (icntype == 'symbol') {
1045 // SVG path symbol
1046 var current_svg = jQuery('.vbo-cust-geo-marker-svg[data-markerapply="1"]');
1047 if (!current_svg.length || !current_svg.first().find('svg').length) {
1048 console.error('no SVG path symbol selected');
1049 alert(Joomla.JText._('VBO_PLEASE_SELECT'));
1050 return false;
1051 }
1052 current_svg = current_svg.first();
1053 // compose selected icon object
1054 var icon_obj = {
1055 id: current_svg.attr('data-markerid'),
1056 name: current_svg.find('.vbo-cust-geo-marker-svg-name').find('span').text(),
1057 group: current_svg.attr('data-markergroup'),
1058 fill: jQuery('#vbo-geo-marker-fillcolor').val(),
1059 opacity: parseFloat(jQuery('#vbo-geo-marker-opacity').val()),
1060 path: current_svg.find('.vbo-cust-geo-marker-svg-icon').find('svg').find('path').attr('d')
1061 };
1062 // check if width and height can be used to set anchor point with X/Y coordinates
1063 var coord_x = current_svg.attr('data-markerpointx');
1064 var coord_y = current_svg.attr('data-markerpointy');
1065 if (coord_x && coord_y) {
1066 icon_obj['anchor'] = {
1067 x: parseFloat(coord_x),
1068 y: parseFloat(coord_y)
1069 };
1070 }
1071
1072 // make a silent AJAX request to update the symbol in the DB or to create it if that's a new icon
1073 var call_method = 'storeSvgSymbol';
1074 jQuery.ajax({
1075 type: "POST",
1076 url: "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=geocoding_endpoint'); ?>",
1077 data: {
1078 tmpl: "component",
1079 callback: call_method,
1080 symbol: icon_obj
1081 }
1082 }).done(function(response) {
1083 try {
1084 var obj_res = JSON.parse(response);
1085 if (!obj_res.hasOwnProperty(call_method)) {
1086 console.error('storeSvgSymbol unexpected JSON response', obj_res);
1087 } else {
1088 // console.log(obj_res[call_method]);
1089 // trigger the geo-saving event
1090 document.dispatchEvent(new Event('vbo-room-geosaving'));
1091 }
1092 } catch(err) {
1093 console.error('storeSvgSymbol could not parse JSON response', err, response);
1094 }
1095 }).fail(function(err) {
1096 console.error('storeSvgSymbol request failed', err);
1097 });
1098
1099 // compose icon symbol object
1100 var symbol_obj = {
1101 path: icon_obj.path,
1102 fillColor: icon_obj.fill,
1103 fillOpacity: icon_obj.opacity,
1104 strokeWeight: 0,
1105 scale: 1,
1106 vbo_icon_id: icon_obj.id
1107 };
1108 // check if anchor point is defined
1109 if (icon_obj.hasOwnProperty('anchor')) {
1110 symbol_obj['anchor'] = icon_obj['anchor'];
1111 }
1112 // update marker icon on map
1113 vbo_geomarker_units[vbo_current_marker_index].setIcon(symbol_obj);
1114 // update icon in global object
1115 if (vbo_geomarker_units_pos !== null && vbo_geomarker_units_pos.hasOwnProperty(vbo_current_marker_index)) {
1116 vbo_geomarker_units_pos[vbo_current_marker_index]['icon'] = symbol_obj;
1117 }
1118 } else if (icntype == 'icon') {
1119 // icon URL (Icon interface)
1120 var custom_icon_url = jQuery('input[name="marker_icon_img"]').val();
1121 if (!custom_icon_url.length) {
1122 console.error('no image selected');
1123 alert(Joomla.JText._('VBO_PLEASE_SELECT'));
1124 return false;
1125 }
1126 if (custom_icon_url.substr(0, 1) == '/') {
1127 custom_icon_url = custom_icon_url.substr(1);
1128 }
1129 var icon_url = vbo_marker_base_uri + custom_icon_url;
1130 var icon_obj = {
1131 url: icon_url
1132 };
1133 var icon_width = jQuery('#vbo-geo-marker-icon-width').val();
1134 var icon_height = jQuery('#vbo-geo-marker-icon-height').val();
1135 if (icon_width && icon_width > 0 && icon_height > 0) {
1136 var scaledSize = {
1137 width: parseInt(icon_width),
1138 height: parseInt(icon_height)
1139 }
1140 icon_obj['scaledSize'] = scaledSize;
1141 }
1142 // update marker icon on map
1143 vbo_geomarker_units[vbo_current_marker_index].setIcon(icon_obj);
1144 // update icon in global object
1145 if (vbo_geomarker_units_pos !== null && vbo_geomarker_units_pos.hasOwnProperty(vbo_current_marker_index)) {
1146 vbo_geomarker_units_pos[vbo_current_marker_index]['icon'] = icon_obj;
1147 }
1148 }
1149
1150 // hide modal
1151 hideVboModalGeoMap();
1152
1153 // trigger the geo-saving event
1154 document.dispatchEvent(new Event('vbo-room-geosaving'));
1155 }
1156
1157 /**
1158 * Removes an SVG symbol from DOM and DB
1159 */
1160 function vboCustomizeMarkerDeleteSymbol(elem) {
1161 if (confirm(Joomla.JText._('VBO_WIDGETS_CONFRMELEM'))) {
1162 var symbol_id = jQuery(elem).closest('.vbo-cust-geo-marker-svg').attr('data-markerid');
1163 if (!symbol_id || !symbol_id.length) {
1164 console.error('symbol id is empty', elem);
1165 return false;
1166 }
1167 // remove the element from the DOM
1168 jQuery(elem).closest('.vbo-cust-geo-marker-svg').remove();
1169 // make a silent AJAX request to remove the symbol from the DB
1170 var call_method = 'deleteSvgSymbol';
1171 jQuery.ajax({
1172 type: "POST",
1173 url: "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=geocoding_endpoint'); ?>",
1174 data: {
1175 tmpl: "component",
1176 callback: call_method,
1177 symbol_id: symbol_id
1178 }
1179 }).done(function(response) {
1180 try {
1181 var obj_res = JSON.parse(response);
1182 if (!obj_res.hasOwnProperty(call_method)) {
1183 console.error('deleteSvgSymbol unexpected JSON response', obj_res);
1184 } else {
1185 // console.log(obj_res[call_method]);
1186 }
1187 } catch(err) {
1188 console.error('deleteSvgSymbol could not parse JSON response', err, response);
1189 }
1190 }).fail(function(err) {
1191 console.error('deleteSvgSymbol request failed', err);
1192 });
1193 }
1194 }
1195
1196 /**
1197 * Toggles the use of a ground overlay image for the map.
1198 */
1199 function vboToggleGeoGroundOverlay() {
1200 if (vbo_geomap === null && vbo_ground_overlay === null) {
1201 console.error('both map and ground overlay are null');
1202 return false;
1203 }
1204 if (jQuery('input[name="geo_goverlay"]').is(':checked')) {
1205 // populate bounds coords, and current image if empty
1206 var south_west = null,
1207 north_east = null;
1208 if (vbo_ground_overlay !== null) {
1209 // get current values from ground overlay
1210 var bounds = vbo_ground_overlay.getBounds();
1211 south_west = bounds.getSouthWest();
1212 north_east = bounds.getNorthEast();
1213 // check if current image is set
1214 if (!jQuery('input[name="map_overlay_img"]').val().length) {
1215 var overlay_url = vbo_ground_overlay.getUrl();
1216 if (overlay_url) {
1217 // set input value
1218 jQuery('input[name="map_overlay_img"]').val(overlay_url.replace(vbo_marker_base_uri, ''));
1219 // try to set the image source (this changes from J to WP)
1220 if (jQuery('.image-preview-wrapper').length) {
1221 jQuery('.vbo-cust-geo-overlay-wrapper').find('.image-preview-wrapper').html('<img src="' + overlay_url + '" />').show();
1222 }
1223 }
1224 }
1225 // display button to copy the current map coordinates because the user may need to adjust the overlay position
1226 jQuery('#vbo-overlay-copy-bounds').show();
1227 } else if (vbo_geomap !== null) {
1228 // get current values from geo map
1229 var bounds = vbo_geomap.getBounds();
1230 south_west = bounds.getSouthWest();
1231 north_east = bounds.getNorthEast();
1232 }
1233 if (south_west !== null && north_east !== null) {
1234 jQuery('#vbo-geo-map-overlay-south').val(south_west.lat());
1235 jQuery('#vbo-geo-map-overlay-west').val(south_west.lng());
1236 jQuery('#vbo-geo-map-overlay-north').val(north_east.lat());
1237 jQuery('#vbo-geo-map-overlay-east').val(north_east.lng());
1238 }
1239 // turn on flag for editing ground overlay
1240 vbo_doing_ground_overlay = true;
1241 // set proper modal title
1242 jQuery('#vbo-modal-geomap-title').html('<?php VikBookingIcons::e('images'); ?> ' + Joomla.JText._('VBO_GEO_MAP_GOVERLAY'));
1243 // open modal
1244 jQuery('.vbo-cust-geo-marker-wrapper').hide();
1245 jQuery('.vbo-cust-geo-overlay-wrapper').show();
1246 vboOpenModalGeoMap();
1247 // lower the z-index of our modal to allow the media-manager modal to be displayed on top
1248 jQuery('.vbo-modal-overlay-block-geomap').addClass('vbo-modal-overlay-block-geomap-lowerzindex');
1249 } else {
1250 // unset the ground overlay, if any
1251 if (vbo_ground_overlay !== null) {
1252 vbo_ground_overlay.setMap(null);
1253 vbo_ground_overlay = null;
1254 }
1255 // hide edit button
1256 jQuery('#vbo-goverlay-edit').hide();
1257 // restore the original z-index of our modal
1258 jQuery('.vbo-modal-overlay-block-geomap').removeClass('vbo-modal-overlay-block-geomap-lowerzindex');
1259 // close modal even though it should be closed already
1260 hideVboModalGeoMap();
1261 // trigger the geo-saving event
1262 document.dispatchEvent(new Event('vbo-room-geosaving'));
1263 }
1264 }
1265
1266 /**
1267 * Applies a ground overlay image to the map.
1268 */
1269 function vboGroundOverlayApply() {
1270 if (vbo_geomap === null) {
1271 console.error('map is null');
1272 return false;
1273 }
1274 var overlay_url = jQuery('input[name="map_overlay_img"]').val();
1275 if (!overlay_url || !overlay_url.length) {
1276 alert(Joomla.JText._('VBO_PLEASE_SELECT'));
1277 return false;
1278 }
1279 var overlay_s = jQuery('#vbo-geo-map-overlay-south').val();
1280 var overlay_w = jQuery('#vbo-geo-map-overlay-west').val();
1281 var overlay_n = jQuery('#vbo-geo-map-overlay-north').val();
1282 var overlay_e = jQuery('#vbo-geo-map-overlay-east').val();
1283 if (!overlay_s.length || !overlay_w.length || !overlay_n.length || !overlay_e.length) {
1284 alert(Joomla.JText._('VBO_PLEASE_SELECT'));
1285 return false;
1286 }
1287 var use_overlay_url = overlay_url;
1288 if (use_overlay_url.indexOf(vbo_marker_base_uri) < 0) {
1289 use_overlay_url = vbo_marker_base_uri + overlay_url;
1290 }
1291 // compose LatLngBounds object
1292 var overlay_bounds = new google.maps.LatLngBounds(
1293 new google.maps.LatLng(parseFloat(overlay_s), parseFloat(overlay_w)),
1294 new google.maps.LatLng(parseFloat(overlay_n), parseFloat(overlay_e))
1295 );
1296 if (vbo_ground_overlay !== null) {
1297 // remove it from the map first
1298 vbo_ground_overlay.setMap(null);
1299 }
1300 // update ground overlay object
1301 vbo_ground_overlay = new google.maps.GroundOverlay(use_overlay_url, overlay_bounds);
1302 // set the overlay to the map
1303 vbo_ground_overlay.setMap(vbo_geomap);
1304 // turn off flag for editing ground overlay
1305 vbo_doing_ground_overlay = false;
1306 // show edit button
1307 jQuery('#vbo-goverlay-edit').show();
1308 // close the modal
1309 hideVboModalGeoMap();
1310 // trigger the geo-saving event
1311 document.dispatchEvent(new Event('vbo-room-geosaving'));
1312 }
1313
1314 /**
1315 * Copies the current map bounds and updates the input fields for the ground overlay coordinates.
1316 */
1317 function vboOverlayCopyBounds() {
1318 if (vbo_geomap === null) {
1319 console.error('map is null');
1320 return false;
1321 }
1322 // get current values from geo map
1323 var bounds = vbo_geomap.getBounds();
1324 var south_west = bounds.getSouthWest();
1325 var north_east = bounds.getNorthEast();
1326 // set values in input fields
1327 jQuery('#vbo-geo-map-overlay-south').val(south_west.lat());
1328 jQuery('#vbo-geo-map-overlay-west').val(south_west.lng());
1329 jQuery('#vbo-geo-map-overlay-north').val(north_east.lat());
1330 jQuery('#vbo-geo-map-overlay-east').val(north_east.lng());
1331 var overlay_url = jQuery('input[name="map_overlay_img"]').val();
1332 if (overlay_url && overlay_url.length) {
1333 // we auto-apply the ground overlay image
1334 vboGroundOverlayApply();
1335 }
1336 }
1337
1338 /**
1339 * Prompts for confirmation for importing geo config from the selected room id.
1340 */
1341 function vboImportGeoConfig(room_id) {
1342 if (!room_id) {
1343 return false;
1344 }
1345 if (isNaN(room_id)) {
1346 console.error('invalid room_id provided', room_id);
1347 return false;
1348 }
1349 if (confirm(Joomla.JText._('VBO_GEO_IMPORT_CONF'))) {
1350 var call_method = 'importRoomGeoConfig';
1351 jQuery.ajax({
1352 type: "POST",
1353 url: "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=geocoding_endpoint'); ?>",
1354 data: {
1355 tmpl: "component",
1356 callback: call_method,
1357 room_id: room_id
1358 }
1359 }).done(function(response) {
1360 try {
1361 var obj_res = JSON.parse(response);
1362 if (!obj_res.hasOwnProperty(call_method)) {
1363 console.error('importRoomGeoConfig unexpected JSON response', obj_res);
1364 } else {
1365 var geo_params = obj_res[call_method];
1366 if (parseInt(geo_params['enabled']) < 1) {
1367 // should never occur, but it would break the entire code
1368 alert('The room selected does not have any geographical information');
1369 return false;
1370 }
1371 // populate internal variables
1372 if (!jQuery('input[name="geo_enabled"]').is(':checked')) {
1373 // enable geo-coding params
1374 jQuery('input[name="geo_enabled"]').trigger('click');
1375 }
1376 // set address
1377 jQuery('#geo_address').val(geo_params['address']);
1378 // set center coordinates
1379 jQuery('#geo_latitude').val(geo_params['latitude']);
1380 jQuery('#geo_longitude').val(geo_params['longitude']);
1381 // set zoom
1382 jQuery('#geo_zoom').val(geo_params['zoom']);
1383 // set map type
1384 jQuery('#geo_mtype').val(geo_params['mtype']);
1385 // set height
1386 jQuery('#geo_height').val(geo_params['height']);
1387 jQuery('#vbo-geo-map').css('height', geo_params['height'] + 'px');
1388 // map markers type
1389 jQuery('#geo_markers_multi').val(geo_params['markers_multi']);
1390 // ground overlay
1391 if (parseInt(geo_params['goverlay']) > 0) {
1392 jQuery('input[name="geo_goverlay"]').prop('checked', true);
1393 jQuery('#vbo-goverlay-edit').show();
1394 } else {
1395 jQuery('input[name="geo_goverlay"]').prop('checked', false);
1396 jQuery('#vbo-goverlay-edit').hide();
1397 }
1398 // main room marker hidden data
1399 jQuery('#geo_marker_lat').val(geo_params['marker_lat']);
1400 jQuery('#geo_marker_lng').val(geo_params['marker_lng']);
1401 jQuery('#geo_marker_hide').val(geo_params['marker_hide']);
1402 // main room marker position object
1403 vbo_geomarker_room_pos = null;
1404 if (parseInt(geo_params['marker_hide']) < 1 && geo_params['marker_lat'].length && geo_params['marker_lng'].length) {
1405 vbo_geomarker_room_pos = {
1406 lat: parseFloat(geo_params['marker_lat']),
1407 lng: parseFloat(geo_params['marker_lng'])
1408 };
1409 }
1410 // room units markers positions
1411 if (geo_params.hasOwnProperty('units_pos') && geo_params['units_pos'].hasOwnProperty('1')) {
1412 vbo_geomarker_units_pos = geo_params['units_pos'];
1413 } else {
1414 vbo_geomarker_units_pos = {};
1415 }
1416 // ground overlay
1417 if (parseInt(geo_params['goverlay']) > 0 && geo_params['overlay_img'].length && (geo_params['overlay_south'] + '').length) {
1418 vbo_dbground_overlay = {
1419 url: geo_params['overlay_img'],
1420 south: geo_params['overlay_south'],
1421 west: geo_params['overlay_west'],
1422 north: geo_params['overlay_north'],
1423 east: geo_params['overlay_east']
1424 };
1425 } else {
1426 vbo_dbground_overlay = null;
1427 }
1428 // let the main function build up the whole map to complete the process
1429 vboInitGeoMap();
1430 }
1431 } catch(err) {
1432 console.error('importRoomGeoConfig could not parse JSON response', err, response);
1433 }
1434 }).fail(function(err) {
1435 console.error('importRoomGeoConfig request failed', err);
1436 });
1437 }
1438 }
1439
1440 /**
1441 * Geo map click handler.
1442 */
1443 function vboGeoMapClickedPos(position) {
1444 if (vbo_geomap === null) {
1445 console.error('map is empty');
1446 return false;
1447 }
1448 if (!position) {
1449 console.error('position is empty');
1450 return false;
1451 }
1452 // calculate limits
1453 var multi_markers = jQuery('#geo_markers_multi').val();
1454 var room_units = jQuery('#room_units').val();
1455 var tot_markers = multi_markers > 0 && room_units > 1 ? room_units : 1;
1456 tot_markers = parseInt(tot_markers);
1457 // iterate through markers
1458 for (var i = 1; i <= tot_markers; i++) {
1459 if (!vbo_geomarker_units_pos.hasOwnProperty(i)) {
1460 // marker for this index is missing, add it to given position
1461 vboManageRoomMarker(i, position);
1462 break;
1463 }
1464 }
1465 // if we reach this point it means all room units have got a marker
1466 return true;
1467 }
1468
1469 /**
1470 * Generates the HTML content for the units marker infowindow.
1471 */
1472 function vboGenerateInfoMarkerContent(index, marker_title) {
1473 marker_title = marker_title ? marker_title : Joomla.JText._('VBODISTFEATURERUNIT') + (index + '');
1474 var infowin_cont = '';
1475 infowin_cont += '<div class="vbo-geomarker-infowin-wrap">';
1476 infowin_cont += ' <h4>' + marker_title + '</h4>';
1477 infowin_cont += ' <div class="vbo-geomarker-infowin-inner">';
1478 infowin_cont += ' <button type="button" class="btn btn-primary" onclick="vboCustomizeMarker(' + index + ');"><?php VikBookingIcons::e('palette'); ?> ' + Joomla.JText._('VBO_GEO_CUSTOMIZE_MARKER') + '</button>';
1479 infowin_cont += ' <button type="button" class="btn btn-danger" onclick="vboRemoveMarker(' + index + ');"><?php VikBookingIcons::e('trash'); ?> ' + Joomla.JText._('VBMAINPAYMENTSDEL') + '</button>';
1480 infowin_cont += ' </div>';
1481 infowin_cont += '</div>';
1482
1483 return infowin_cont;
1484 }
1485
1486 /**
1487 * Generates the HTML content for the main room (base address) marker infowindow.
1488 */
1489 function vboGenerateMainInfoMarkerContent() {
1490 var infowin_cont = '';
1491 infowin_cont += '<div class="vbo-geomarker-infowin-wrap vbo-geomarker-address-infowin-wrap">';
1492 infowin_cont += ' <h4>' + Joomla.JText._('VBO_GEO_ADDRESS') + '</h4>';
1493 infowin_cont += ' <div class="vbo-geomarker-infowin-inner">';
1494 infowin_cont += ' <button type="button" class="btn btn-secondary" onclick="vboRemoveAddressMarker();"><?php VikBookingIcons::e('trash'); ?> ' + Joomla.JText._('VBO_GEO_HIDE_FROM_MAP') + '</button>';
1495 infowin_cont += ' </div>';
1496 infowin_cont += '</div>';
1497
1498 return infowin_cont;
1499 }
1500
1501 /**
1502 * Saves the geo information for this room in a transient-like record.
1503 * The controller will then resume this transient to store the geo params.
1504 */
1505 function vboHandleGeoSaving() {
1506 if (vbo_geomap === null) {
1507 console.error('saving is useless as the map is null');
1508 return false;
1509 }
1510 // turn on flag for saving
1511 vbo_geomap_saving = true;
1512 // make a silent AJAX request to store the current room geo information
1513 var call_method = 'updateRoomGeoTransient';
1514 jQuery.ajax({
1515 type: "POST",
1516 url: "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=geocoding_endpoint'); ?>",
1517 data: {
1518 tmpl: "component",
1519 callback: call_method,
1520 room_id: <?php echo count($this->row) ? $this->row['id'] : '0'; ?>,
1521 geo_enabled: (jQuery('input[name="geo_enabled"]').is(':checked') ? 1 : 0),
1522 geo_address: jQuery('#geo_address').val(),
1523 geo_latitude: jQuery('#geo_latitude').val(),
1524 geo_longitude: jQuery('#geo_longitude').val(),
1525 geo_zoom: jQuery('#geo_zoom').val(),
1526 geo_mtype: jQuery('#geo_mtype').val(),
1527 geo_height: jQuery('#geo_height').val(),
1528 geo_markers_multi: jQuery('#geo_markers_multi').val(),
1529 geo_marker_lat: jQuery('#geo_marker_lat').val(),
1530 geo_marker_lng: jQuery('#geo_marker_lng').val(),
1531 geo_marker_hide: jQuery('#geo_marker_hide').val(),
1532 geo_units_pos: vbo_geomarker_units_pos,
1533 geo_goverlay: (jQuery('input[name="geo_goverlay"]').is(':checked') ? 1 : 0),
1534 geo_overlay_img: (jQuery('input[name="map_overlay_img"]').val().length ? (vbo_marker_base_uri + jQuery('input[name="map_overlay_img"]').val()) : ''),
1535 geo_overlay_south: jQuery('#vbo-geo-map-overlay-south').val(),
1536 geo_overlay_west: jQuery('#vbo-geo-map-overlay-west').val(),
1537 geo_overlay_north: jQuery('#vbo-geo-map-overlay-north').val(),
1538 geo_overlay_east: jQuery('#vbo-geo-map-overlay-east').val()
1539 }
1540 }).done(function(response) {
1541 try {
1542 var obj_res = JSON.parse(response);
1543 if (!obj_res.hasOwnProperty(call_method)) {
1544 console.error('updateRoomGeoTransient unexpected JSON response', obj_res);
1545 } else {
1546 // console.log(obj_res[call_method]);
1547 }
1548 } catch(err) {
1549 console.error('updateRoomGeoTransient could not parse JSON response', err, response);
1550 }
1551 // turn off flag for saving
1552 vbo_geomap_saving = false;
1553 }).fail(function(err) {
1554 console.error('updateRoomGeoTransient request failed', err);
1555 });
1556 //
1557 }
1558
1559 jQuery(document).ready(function() {
1560
1561 // display geocoding params, if necessary
1562 vboToggleGeoParams();
1563
1564 // init geo map with current markers, if any
1565 vboInitGeoMap();
1566
1567 // listener to the geocode-address change event with debounce handler.
1568 document.addEventListener('vbo-geocode-address', vboDebounceEvent(vboAddressGeocoding, 500));
1569
1570 // listener to the change-address event
1571 jQuery('#geo_address').keyup(function(e) {
1572 if (e.keyCode && e.keyCode == 13) {
1573 // if enter is pressed, launch the function immediately
1574 vboAddressGeocoding();
1575 return;
1576 }
1577 // trigger the geocode-address change event debounced
1578 document.dispatchEvent(new Event('vbo-geocode-address'));
1579 });
1580
1581 // listener to the change-center event
1582 jQuery('#geo_latitude, #geo_longitude').change(function() {
1583 var lat = jQuery('#geo_latitude').val(),
1584 lng = jQuery('#geo_longitude').val();
1585 vboSetGeoMapCenter(lat, lng);
1586 // trigger the geo-saving event
1587 document.dispatchEvent(new Event('vbo-room-geosaving'));
1588 });
1589
1590 // listener to the change-zoom event
1591 jQuery('#geo_zoom').change(function() {
1592 var zoom = parseFloat(jQuery(this).val());
1593 if (vbo_geomap === null || isNaN(zoom)) {
1594 return;
1595 }
1596 vbo_geomap.setZoom(zoom);
1597 // trigger the geo-saving event
1598 document.dispatchEvent(new Event('vbo-room-geosaving'));
1599 });
1600
1601 // listener to the change-map-type event
1602 jQuery('#geo_mtype').change(function() {
1603 var mtype = jQuery(this).val();
1604 if (vbo_geomap === null) {
1605 return;
1606 }
1607 vbo_geomap.setMapTypeId(mtype);
1608 // trigger the geo-saving event
1609 document.dispatchEvent(new Event('vbo-room-geosaving'));
1610 });
1611
1612 // listener to address suggestion
1613 jQuery('#geo_address_formatted').click(function() {
1614 var address_format = jQuery(this).text();
1615 if (address_format.length < 2) {
1616 return;
1617 }
1618 jQuery('#geo_address').val(address_format);
1619 jQuery(this).text('');
1620 // trigger the geo-saving event
1621 document.dispatchEvent(new Event('vbo-room-geosaving'));
1622 });
1623
1624 // listener to map height change
1625 jQuery('#geo_height').change(function() {
1626 jQuery('#vbo-geo-map').css('height', jQuery(this).val() + 'px');
1627 // trigger the geo-saving event
1628 document.dispatchEvent(new Event('vbo-room-geosaving'));
1629 });
1630
1631 // listener to room main name to update the marker's title
1632 jQuery('input[name="cname"]').change(function() {
1633 if (vbo_geomarker_room === null) {
1634 return;
1635 }
1636 vbo_geomarker_room.setTitle(jQuery(this).val());
1637 });
1638
1639 // listener to map markers quantity change
1640 jQuery('#geo_markers_multi').change(function() {
1641 var mmtype = jQuery(this).val();
1642 if (parseInt(mmtype) == 1) {
1643 // one for each sub-unit, make sure the room has got enough units
1644 var now_units = jQuery('#room_units').val();
1645 if (now_units < 2) {
1646 alert(Joomla.JText._('VBO_GEO_MARKERS_MULTI_ERRUNIT'));
1647 jQuery('#geo_markers_multi').val(0);
1648 }
1649 }
1650 // update map markers
1651 vboPopulateMapMarkers();
1652 // trigger the geo-saving event
1653 document.dispatchEvent(new Event('vbo-room-geosaving'));
1654 });
1655
1656 // register colorpicker
1657 jQuery('.vbo-inspector-colorpicker').ColorPicker({
1658 color: '#ffffff',
1659 onShow: function (colpkr, el) {
1660 if (!jQuery('.vbo-cust-geo-marker-svg[data-markerapply="1"]').length) {
1661 return false;
1662 }
1663 var cur_color = jQuery(el).css('backgroundColor');
1664 jQuery(el).ColorPickerSetColor(vboRgb2Hex(cur_color));
1665 jQuery(colpkr).show();
1666 return false;
1667 },
1668 onChange: function (hsb, hex, rgb, el) {
1669 var element = jQuery(el);
1670 element.css('backgroundColor', '#'+hex);
1671 if (jQuery('.vbo-cust-geo-marker-svg[data-markerapply="1"]').length) {
1672 jQuery('.vbo-cust-geo-marker-svg[data-markerapply="1"]').first().find('svg').css('fill', '#'+hex);
1673 }
1674 jQuery('#vbo-geo-marker-fillcolor').val('#'+hex);
1675 },
1676 onSubmit: function(hsb, hex, rgb, el) {
1677 var element = jQuery(el);
1678 element.css('backgroundColor', '#'+hex);
1679 if (jQuery('.vbo-cust-geo-marker-svg[data-markerapply="1"]').length) {
1680 jQuery('.vbo-cust-geo-marker-svg[data-markerapply="1"]').first().find('svg').css('fill', '#'+hex);
1681 }
1682 jQuery('#vbo-geo-marker-fillcolor').val('#'+hex);
1683 element.ColorPickerHide();
1684 }
1685 });
1686
1687 // register opacity change
1688 jQuery('#vbo-geo-marker-opacity').change(function() {
1689 var opacity = jQuery(this).val();
1690 if (!jQuery('.vbo-cust-geo-marker-svg[data-markerapply="1"]').length) {
1691 return;
1692 }
1693 jQuery('.vbo-cust-geo-marker-svg[data-markerapply="1"]').first().find('svg').css('opacity', opacity);
1694 });
1695
1696 // register select2 for importing geo configuration from another room
1697 if (jQuery('#vbo-geo-importfrom').length) {
1698 jQuery('#vbo-geo-importfrom').select2({
1699 placeholder: Joomla.JText._('VBO_GEO_IMPORT_FROM'),
1700 width: '190px',
1701 allowClear: true
1702 });
1703 }
1704
1705 /**
1706 * Add event listener to the geo-saving event with debounce handler.
1707 */
1708 document.addEventListener('vbo-room-geosaving', vboDebounceEvent(vboHandleGeoSaving, 500));
1709
1710 });
1711 </script>
1712 <?php
1713 }
1714