001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.gwt.client.ui.input.location; 029 030import org.opencms.gwt.client.Messages; 031import org.opencms.gwt.client.rpc.CmsLog; 032import org.opencms.gwt.client.ui.CmsErrorDialog; 033import org.opencms.gwt.client.ui.CmsPopup; 034import org.opencms.gwt.client.util.CmsClientStringUtil; 035import org.opencms.gwt.client.util.CmsDomUtil; 036import org.opencms.util.CmsStringUtil; 037 038import java.util.ArrayList; 039import java.util.Collections; 040import java.util.LinkedHashMap; 041import java.util.List; 042import java.util.Map; 043 044import com.google.gwt.core.client.JavaScriptObject; 045import com.google.gwt.event.logical.shared.ValueChangeEvent; 046import com.google.gwt.user.client.Command; 047import com.google.gwt.user.client.ui.SuggestOracle; 048 049/** 050 * The location picker controller.<p> 051 */ 052public class CmsLocationController { 053 054 /** Flag indicating the API is currently being loaded. */ 055 private static boolean loadingApi; 056 057 /** Flag indicating the dynamic error style has been inserted. */ 058 private static boolean m_hasInsertedDynamicStyle; 059 060 /** The main API param. */ 061 private static final String MAPS_MAIN_PARAM = "v=3.exp"; 062 063 /** The places library param. */ 064 private static final String MAPS_PLACES_PARAM = "libraries=places"; 065 066 /** The URI of google maps API. */ 067 private static final String MAPS_URI = "https://maps.googleapis.com/maps/api/js"; 068 069 /** The callback to be executed once the API is loaded. */ 070 private static List<Command> onApiReady = new ArrayList<Command>(); 071 072 /** The parsed configuration JSON object. */ 073 private JavaScriptObject m_config; 074 075 /** The previous value. */ 076 private CmsLocationValue m_currentValue; 077 078 /** The current location value. */ 079 private CmsLocationValue m_editValue; 080 081 /** The goe coder instance. */ 082 private JavaScriptObject m_geocoder; 083 084 /** The map. */ 085 private JavaScriptObject m_map; 086 087 /** The map marker. */ 088 private JavaScriptObject m_marker; 089 090 /** The picker widget. */ 091 private CmsLocationPicker m_picker; 092 093 /** The popup displaying the map. */ 094 private CmsPopup m_popup; 095 096 /** The popup content widget. */ 097 private CmsLocationPopupContent m_popupContent; 098 099 /** The preview map. */ 100 private JavaScriptObject m_previewMap; 101 102 /** The preview map marker. */ 103 private JavaScriptObject m_previewMarker; 104 105 /** 106 * Constructor.<p> 107 * 108 * @param picker the picker widget 109 * @param configuration the widget configuration 110 */ 111 public CmsLocationController(CmsLocationPicker picker, String configuration) { 112 113 parseConfig(configuration); 114 initDynamicStyle(); 115 m_picker = picker; 116 m_editValue = CmsLocationValue.parse( 117 "{\"address\": \"London\", \"lat\": 51.5001524, \"lng\": -0.1262362, \"height\": 300, \"width\": 400, \"mode\": \"\", \"type\":\"roadmap\", \"zoom\": 8}"); 118 m_currentValue = m_editValue.cloneValue(); 119 } 120 121 /** 122 * Called once the API is loaded.<p> 123 */ 124 private static void apiReady() { 125 126 loadingApi = false; 127 for (Command callback : onApiReady) { 128 callback.execute(); 129 } 130 onApiReady.clear(); 131 } 132 133 /** 134 * Returns the available map modes.<p> 135 * 136 * @return the available map modes 137 */ 138 private static Map<String, String> getModeItems() { 139 140 Map<String, String> modes = new LinkedHashMap<String, String>(); 141 modes.put("dynamic", Messages.get().key(Messages.GUI_LOCATION_DYNAMIC_0)); 142 modes.put("static", Messages.get().key(Messages.GUI_LOCATION_STATIC_0)); 143 return modes; 144 } 145 146 /** 147 * Returns the available map types.<p> 148 * 149 * @return the available map types 150 */ 151 private static Map<String, String> getTypeItems() { 152 153 Map<String, String> types = new LinkedHashMap<String, String>(); 154 types.put("roadmap", Messages.get().key(Messages.GUI_LOCATION_ROADMAP_0)); 155 types.put("hybrid", Messages.get().key(Messages.GUI_LOCATION_HYBRID_0)); 156 types.put("satellite", Messages.get().key(Messages.GUI_LOCATION_SATELLITE_0)); 157 types.put("terrain", Messages.get().key(Messages.GUI_LOCATION_TERRAIN_0)); 158 return types; 159 } 160 161 /** 162 * Returns the available zoom levels.<p> 163 * 164 * @return the available zoom levels 165 */ 166 private static Map<String, String> getZoomItems() { 167 168 Map<String, String> zoomItems = new LinkedHashMap<String, String>(); 169 for (int i = 0; i < 21; i++) { 170 String value = String.valueOf(i); 171 zoomItems.put(value, value); 172 } 173 return zoomItems; 174 } 175 176 /** 177 * Returns if the google maps API is already loaded to the window context.<p> 178 * 179 * @return <code>true</code> if the google maps API is already loaded to the window context 180 */ 181 private static boolean isApiLoaded() { 182 183 return isMainApiLoaded() && isPlacesApiLoaded(); 184 } 185 186 /** 187 * Returns if the google maps API is already loaded to the window context.<p> 188 * 189 * @return <code>true</code> if the google maps API is already loaded to the window context 190 */ 191 private static native boolean isMainApiLoaded()/*-{ 192 var result = $wnd.google !== undefined 193 && $wnd.google.maps !== undefined 194 && $wnd.google.maps.Map !== undefined; 195 return result; 196 }-*/; 197 198 /** 199 * Returns if the google maps API is already loaded to the window context.<p> 200 * 201 * @return <code>true</code> if the google maps API is already loaded to the window context 202 */ 203 private static native boolean isPlacesApiLoaded()/*-{ 204 var result = $wnd.google !== undefined 205 && $wnd.google.maps !== undefined 206 && $wnd.google.maps.places !== undefined; 207 return result; 208 }-*/; 209 210 /** 211 * Returns the current location value.<p> 212 * 213 * @return the location value 214 */ 215 public CmsLocationValue getLocationValue() { 216 217 return m_editValue; 218 } 219 220 /** 221 * Returns the JSON string representation of the current value.<p> 222 * 223 * @return the JSON string representation 224 */ 225 public String getStringValue() { 226 227 return m_currentValue == null ? "" : m_currentValue.toJSONString(); 228 } 229 230 /** Sets the location value as string. 231 * 232 * @param value the string representation of the location value (JSON) 233 **/ 234 public void setStringValue(String value) { 235 236 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(value)) { 237 try { 238 m_editValue = CmsLocationValue.parse(value); 239 m_currentValue = m_editValue.cloneValue(); 240 displayValue(); 241 if ((m_popup != null) && m_popup.isVisible()) { 242 m_popupContent.displayValues(m_editValue); 243 updateMarkerPosition(); 244 } 245 } catch (Exception e) { 246 CmsLog.log(e.getLocalizedMessage() + "\n" + CmsClientStringUtil.getStackTrace(e, "\n")); 247 } 248 } else { 249 m_currentValue = null; 250 displayValue(); 251 } 252 } 253 254 /** 255 * Return a maps API position object according the the current location value.<p> 256 * 257 * @return the position object 258 */ 259 protected native JavaScriptObject getCurrentPosition()/*-{ 260 var val = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue; 261 return new $wnd.google.maps.LatLng(val.lat, val.lng); 262 263 }-*/; 264 265 /** 266 * Called on address value change.<p> 267 * 268 * @param address the new address 269 */ 270 protected native void onAddressChange(String address) /*-{ 271 var self = this; 272 this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue.address = address; 273 this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_geocoder 274 .geocode( 275 { 276 'address' : address 277 }, 278 function(results, status) { 279 // check to see if we have at least one valid address 280 if (!results 281 || (status != $wnd.google.maps.GeocoderStatus.OK) 282 || !results[0].formatted_address) { 283 alert("Address not found"); 284 return; 285 } 286 var lat = results[0].geometry.location.lat(); 287 var lng = results[0].geometry.location.lng(); 288 self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::setPosition(FFZZ)(lat,lng,true,false); 289 }); 290 }-*/; 291 292 /** 293 * Called on address suggestion selection.<p> 294 * 295 * @param suggestion the selected suggestion 296 */ 297 protected void onAddressChange(SuggestOracle.Suggestion suggestion) { 298 299 try { 300 onAddressChange(suggestion.getDisplayString()); 301 } catch (Throwable t) { 302 CmsErrorDialog.handleException(t); 303 } 304 } 305 306 /** 307 * Cancels the location selection.<p> 308 */ 309 protected void onCancel() { 310 311 m_popup.hide(); 312 if (m_currentValue != null) { 313 m_editValue = m_currentValue; 314 } 315 displayValue(); 316 } 317 318 /** 319 * Called on height value change.<p> 320 * 321 * @param height the height 322 */ 323 protected void onHeightChange(String height) { 324 325 m_editValue.setHeight(height); 326 } 327 328 /** 329 * Called on latitude value change.<p> 330 * 331 * @param latitude the latitude 332 */ 333 protected void onLatitudeChange(String latitude) { 334 335 try { 336 m_editValue.setLatitude(latitude); 337 updateMarkerPosition(); 338 updateAddress(); 339 } catch (Throwable t) { 340 CmsErrorDialog.handleException(t); 341 } 342 } 343 344 /** 345 * Called on longitude value change.<p> 346 * 347 * @param longitude the longitude 348 */ 349 protected void onLongitudeChange(String longitude) { 350 351 try { 352 m_editValue.setLongitude(longitude); 353 updateMarkerPosition(); 354 updateAddress(); 355 } catch (Throwable t) { 356 CmsErrorDialog.handleException(t); 357 } 358 } 359 360 /** 361 * Called on mode value change.<p> 362 * 363 * @param mode the mode 364 */ 365 protected void onModeChange(String mode) { 366 367 m_editValue.setMode(mode); 368 } 369 370 /** 371 * Sets the selected location value.<p> 372 */ 373 protected void onOk() { 374 375 ensureFormattedAddress(); 376 } 377 378 /** 379 * Ensures the preview map has the right size and is centered.<p> 380 */ 381 protected native void onPreviewResize()/*-{ 382 var map = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_previewMap; 383 if (map != null) { 384 $wnd.google.maps.event.trigger(map, 'resize'); 385 var pos = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::getCurrentPosition()(); 386 map.setCenter(pos); 387 } 388 }-*/; 389 390 /** 391 * Called on map type change.<p> 392 * 393 * @param type the map type 394 */ 395 protected native void onTypeChange(String type)/*-{ 396 this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue.type = type; 397 this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_map 398 .setMapTypeId(type); 399 }-*/; 400 401 /** 402 * Called on width value change.<p> 403 * 404 * @param width the width 405 */ 406 protected void onWidthChange(String width) { 407 408 m_editValue.setWidth(width); 409 } 410 411 /** 412 * Called on zoom value change.<p> 413 * 414 * @param zoom the zoom 415 */ 416 protected native void onZoomChange(String zoom) /*-{ 417 var z = parseInt(zoom); 418 if (!isNaN(z)) { 419 this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue.zoom = z; 420 var map = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_map; 421 map.setZoom(z); 422 var pos = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::getCurrentPosition()(); 423 map.panTo(pos); 424 map.setCenter(pos); 425 } 426 }-*/; 427 428 /** 429 * Fires the value change event for the location picker.<p> 430 * 431 * @param force <code>true</code> to always fire the event 432 */ 433 void fireChangeEventOnPicker(boolean force) { 434 435 String val = m_editValue.toJSONString(); 436 if (force || (m_currentValue == null) || !val.equals(m_currentValue.toJSONString())) { 437 m_currentValue = m_editValue.cloneValue(); 438 displayValue(); 439 ValueChangeEvent.fire(m_picker, val); 440 } 441 } 442 443 /** 444 * Displays the map for the current location.<p> 445 */ 446 native void initMap() /*-{ 447 try { 448 if (this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_map == null) { 449 var value = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue; 450 var type = (value.type == null || value.type == "") ? "roadmap" 451 : value.type; 452 var zoom = parseInt(value.zoom); 453 if (isNaN(zoom)) { 454 zoom = 8; 455 } 456 457 var mapOptions = { 458 zoom : zoom, 459 mapTypeId : type, 460 center : new $wnd.google.maps.LatLng(-34.397, 150.644), 461 streetViewControl : false 462 }; 463 var popupContent = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_popupContent; 464 var canvas = popupContent.@org.opencms.gwt.client.ui.input.location.CmsLocationPopupContent::getMapCanvas()(); 465 this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_map = new $wnd.google.maps.Map( 466 canvas, mapOptions); 467 this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_geocoder = new $wnd.google.maps.Geocoder(); 468 } 469 } catch (e) { 470 $wnd.console.log(e.message); 471 } 472 this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::updateMarkerPosition()(); 473 }-*/; 474 475 /** 476 * Opens the location picker popup.<p> 477 */ 478 void openPopup() { 479 480 try { 481 if (m_popup == null) { 482 m_popup = new CmsPopup(Messages.get().key(Messages.GUI_LOCATION_DIALOG_TITLE_0), hasMap() ? 1020 : 420); 483 m_popupContent = new CmsLocationPopupContent( 484 this, 485 new CmsLocationSuggestOracle(this), 486 getModeItems(), 487 getTypeItems(), 488 getZoomItems()); 489 setFieldVisibility(); 490 m_popup.setMainContent(m_popupContent); 491 m_popup.addDialogClose(null); 492 } 493 m_popup.center(); 494 m_popup.show(); 495 initialize(); 496 updateForm(); 497 } catch (Throwable t) { 498 CmsErrorDialog.handleException(t); 499 } 500 } 501 502 /** 503 * Displays the values within the picker widget.<p> 504 */ 505 private void displayValue() { 506 507 if (m_currentValue == null) { 508 m_picker.displayValue(""); 509 m_picker.setPreviewVisible(false); 510 m_picker.setLocationInfo(Collections.<String, String> emptyMap()); 511 } else { 512 m_picker.displayValue(m_editValue.getAddress()); 513 Map<String, String> infos = new LinkedHashMap<String, String>(); 514 if (hasLatLng()) { 515 infos.put(Messages.get().key(Messages.GUI_LOCATION_LATITUDE_0), m_editValue.getLatitudeString()); 516 infos.put(Messages.get().key(Messages.GUI_LOCATION_LONGITUDE_0), m_editValue.getLongitudeString()); 517 infos.put(Messages.get().key(Messages.GUI_LOCATION_ZOOM_0), String.valueOf(m_editValue.getZoom())); 518 } 519 if (hasSize()) { 520 infos.put( 521 Messages.get().key(Messages.GUI_LOCATION_SIZE_0), 522 m_editValue.getWidth() + " x " + m_editValue.getHeight()); 523 } 524 if (hasType()) { 525 infos.put(Messages.get().key(Messages.GUI_LOCATION_TYPE_0), m_editValue.getType()); 526 } 527 if (hasMode()) { 528 infos.put(Messages.get().key(Messages.GUI_LOCATION_MODE_0), m_editValue.getMode()); 529 } 530 m_picker.setLocationInfo(infos); 531 m_picker.setPreviewVisible(true); 532 if (!isApiLoaded()) { 533 534 onApiReady(new Command() { 535 536 public void execute() { 537 538 return; 539 } 540 }); 541 } 542 } 543 } 544 545 /** 546 * Checks the current address with the google geocoder to ensure a well formatted address.<p> 547 * Will close the picker popup afterwards.<p> 548 */ 549 private native void ensureFormattedAddress()/*-{ 550 var self = this; 551 var address = self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue.address; 552 if (address != null && address.trim().length > 0) { 553 self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_geocoder 554 .geocode( 555 { 556 'address' : address 557 }, 558 function(results, status) { 559 // check to see if we have at least one valid address 560 if (results 561 && (status == $wnd.google.maps.GeocoderStatus.OK) 562 && results[0].formatted_address) { 563 self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue.address = results[0].formatted_address; 564 } 565 self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::fireChangeAndClose()(); 566 }); 567 } 568 self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::fireChangeAndClose()(); 569 }-*/; 570 571 /** 572 * Fires the value change event and closes the picker popup.<p> 573 */ 574 private void fireChangeAndClose() { 575 576 fireChangeEventOnPicker(false); 577 m_popup.hide(); 578 } 579 580 /** 581 * Returns the Google API key.<p> 582 * 583 * @return the Google API key 584 */ 585 private native String getAPIKey()/*-{ 586 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.apiKey; 587 }-*/; 588 589 /** 590 * Returns the Google API key message.<p> 591 * 592 * @return the Google API key message 593 */ 594 private native String getAPIKeyMessage()/*-{ 595 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.apiKeyMessage; 596 }-*/; 597 598 /** 599 * Returns the value display string.<p> 600 * 601 * @return the value 602 */ 603 private String getDisplayString() { 604 605 return Messages.get().key( 606 Messages.GUI_LOCATION_DISPLAY_3, 607 m_editValue.getAddress(), 608 m_editValue.getLatitudeString(), 609 m_editValue.getLongitudeString()); 610 } 611 612 /** 613 * Evaluates if the address field is configured.<p> 614 * 615 * @return <code>true</code> if the address field is configured 616 */ 617 private native boolean hasAddress()/*-{ 618 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit 619 .indexOf('address') != -1; 620 }-*/; 621 622 /** 623 * Evaluates if the Google API key is configured.<p> 624 * 625 * @return <code>true</code> if the Google API key is configured 626 */ 627 private native boolean hasAPIKey()/*-{ 628 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config != null 629 && this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.apiKey != null; 630 }-*/; 631 632 /** 633 * Evaluates if the lat. lng. fields are configured.<p> 634 * 635 * @return <code>true</code> if the lat. lng. fields are configured 636 */ 637 private native boolean hasLatLng()/*-{ 638 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit 639 .indexOf('coords') != -1; 640 }-*/; 641 642 /** 643 * Evaluates if the map field is configured.<p> 644 * 645 * @return <code>true</code> if the map field is configured 646 */ 647 private native boolean hasMap()/*-{ 648 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit 649 .indexOf('map') != -1; 650 }-*/; 651 652 /** 653 * Evaluates if the mode field is configured.<p> 654 * 655 * @return <code>true</code> if the mode field is configured 656 */ 657 private native boolean hasMode()/*-{ 658 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit 659 .indexOf('mode') != -1; 660 }-*/; 661 662 /** 663 * Evaluates if the size fields are configured.<p> 664 * 665 * @return <code>true</code> if the size fields are configured 666 */ 667 private native boolean hasSize()/*-{ 668 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit 669 .indexOf('size') != -1; 670 }-*/; 671 672 /** 673 * Evaluates if the type field is configured.<p> 674 * 675 * @return <code>true</code> if the type field is configured 676 */ 677 private native boolean hasType()/*-{ 678 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit 679 .indexOf('type') != -1; 680 }-*/; 681 682 /** 683 * Evaluates if the zoom field is configured.<p> 684 * 685 * @return <code>true</code> if the zoom field is configured 686 */ 687 private native boolean hasZoom()/*-{ 688 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit 689 .indexOf('zoom') != -1; 690 }-*/; 691 692 /** 693 * Adds a CSS style rule to display the localized error message on missing API key.<p> 694 */ 695 private void initDynamicStyle() { 696 697 if (!m_hasInsertedDynamicStyle) { 698 String message = Messages.get().key(Messages.ERR_LOCATION_MISSING_API_KEY_1, "\\a"); 699 message.replace("<br />", "\\\\a"); 700 CmsDomUtil.addDynamicStyleRule( 701 "div.gm-err-content:after, div.mapPreview > div > div:empty:after{ content:'" 702 + message 703 + "' !important; }"); 704 m_hasInsertedDynamicStyle = true; 705 } 706 } 707 708 /** 709 * Initializes the location picker.<p> 710 */ 711 private void initialize() { 712 713 if (isApiLoaded()) { 714 initMap(); 715 } else { 716 onApiReady(new Command() { 717 718 public void execute() { 719 720 initMap(); 721 } 722 }); 723 } 724 } 725 726 /** 727 * Loads the google maps API and initializes the map afterwards.<p> 728 */ 729 private native void loadApi()/*-{ 730 $wnd.cmsLocationPickerApiReady = function() { 731 @org.opencms.gwt.client.ui.input.location.CmsLocationController::apiReady()(); 732 } 733 var uri = @org.opencms.gwt.client.ui.input.location.CmsLocationController::MAPS_URI; 734 uri += '?' 735 + @org.opencms.gwt.client.ui.input.location.CmsLocationController::MAPS_MAIN_PARAM 736 + '&' 737 + @org.opencms.gwt.client.ui.input.location.CmsLocationController::MAPS_PLACES_PARAM; 738 if (this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::hasAPIKey()()) { 739 uri += '&key=' 740 + this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::getAPIKey()(); 741 if ($wnd.console) { 742 $wnd.console 743 .log(this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::getAPIKeyMessage()()); 744 } 745 } else if ($wnd.console) { 746 $wnd.console.log("No Google API key available"); 747 } 748 uri += '&callback=cmsLocationPickerApiReady'; 749 750 var script = $wnd.document.createElement('script'); 751 script.src = uri; 752 $wnd.document.body.appendChild(script); 753 }-*/; 754 755 /** 756 * Adds a callback to be executed once the API is ready. Will be executed right away if the API is already loaded.<p> 757 * 758 * @param callback the callback 759 */ 760 private void onApiReady(Command callback) { 761 762 if (isApiLoaded()) { 763 callback.execute(); 764 } else { 765 onApiReady.add(callback); 766 if (!loadingApi) { 767 loadingApi = true; 768 loadApi(); 769 } 770 } 771 } 772 773 /** 774 * Parses the configuration string.<p> 775 * 776 * @param configuration the configuration 777 */ 778 private native void parseConfig(String configuration)/*-{ 779 this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config = JSON 780 .parse(configuration); 781 }-*/; 782 783 /** 784 * Sets all editable fields visible.<p> 785 */ 786 private void setFieldVisibility() { 787 788 m_popupContent.setMapVisible(hasMap()); 789 m_popupContent.setAddressVisible(hasAddress()); 790 m_popupContent.setLatLngVisible(hasLatLng()); 791 m_popupContent.setSizeVisible(hasSize()); 792 m_popupContent.setTypeVisible(hasType()); 793 m_popupContent.setModeVisible(hasMode()); 794 m_popupContent.setZoomVisible(hasZoom()); 795 } 796 797 /** 798 * Sets the position values and updates the map view.<p> 799 * 800 * @param latitude the latitude 801 * @param longitude the longitude 802 * @param updateMap <code>true</code> to update the map 803 * @param updateAddress <code>true</code> to update the address from the new position data 804 */ 805 private void setPosition(float latitude, float longitude, boolean updateMap, boolean updateAddress) { 806 807 m_editValue.setLatitude(latitude); 808 m_editValue.setLongitude(longitude); 809 m_popupContent.displayValues(m_editValue); 810 if (updateMap) { 811 updateMarkerPosition(); 812 } 813 if (updateAddress) { 814 updateAddress(); 815 } 816 } 817 818 /** 819 * Updates the address according to the current position data.<p> 820 */ 821 private native void updateAddress()/*-{ 822 var self = this; 823 var pos = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::getCurrentPosition()(); 824 // try to evaluate the address from the current position 825 this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_geocoder 826 .geocode( 827 { 828 'latLng' : pos 829 }, 830 function(results, status) { 831 var address = ""; 832 // check that everything is ok 833 if (status == $wnd.google.maps.GeocoderStatus.OK 834 && results[0] 835 && results[0].formatted_address) { 836 // set the new address 837 address = results[0].formatted_address; 838 } 839 if (address != self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue.address) { 840 self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue.address = address; 841 self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::updateForm()(); 842 } 843 }); 844 }-*/; 845 846 /** 847 * Displays the current location value within the popup form.<p> 848 */ 849 private void updateForm() { 850 851 m_popupContent.displayValues(m_editValue); 852 } 853 854 /** 855 * Updates the marker position according to the current location value.<p> 856 */ 857 private native void updateMarkerPosition()/*-{ 858 var map = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_map; 859 var pos = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::getCurrentPosition()(); 860 var marker = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_marker; 861 if (marker == null) { 862 try { 863 var marker = new $wnd.google.maps.Marker({ 864 position : pos, 865 map : map, 866 draggable : true 867 }); 868 this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_marker = marker; 869 var self = this; 870 // handle marker dnd 871 $wnd.google.maps.event 872 .addListener( 873 marker, 874 "dragend", 875 function() { 876 var lat = marker.getPosition().lat(); 877 var lng = marker.getPosition().lng(); 878 self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::setPosition(FFZZ)(lat,lng,false,true); 879 }); 880 } catch (e) { 881 $wnd.alert(e.message); 882 } 883 } else { 884 marker.setPosition(pos); 885 } 886 map.panTo(pos); 887 map.setCenter(pos); 888 }-*/; 889 890}