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(() -> updateForm()); 496 } catch (Throwable t) { 497 CmsErrorDialog.handleException(t); 498 } 499 } 500 501 /** 502 * Displays the values within the picker widget.<p> 503 */ 504 private void displayValue() { 505 506 if (m_currentValue == null) { 507 m_picker.displayValue(""); 508 m_picker.setPreviewVisible(false); 509 m_picker.setLocationInfo(Collections.<String, String> emptyMap()); 510 } else { 511 m_picker.displayValue(m_editValue.getAddress()); 512 Map<String, String> infos = new LinkedHashMap<String, String>(); 513 if (hasLatLng()) { 514 infos.put(Messages.get().key(Messages.GUI_LOCATION_LATITUDE_0), m_editValue.getLatitudeString()); 515 infos.put(Messages.get().key(Messages.GUI_LOCATION_LONGITUDE_0), m_editValue.getLongitudeString()); 516 infos.put(Messages.get().key(Messages.GUI_LOCATION_ZOOM_0), String.valueOf(m_editValue.getZoom())); 517 } 518 if (hasSize()) { 519 infos.put( 520 Messages.get().key(Messages.GUI_LOCATION_SIZE_0), 521 m_editValue.getWidth() + " x " + m_editValue.getHeight()); 522 } 523 if (hasType()) { 524 infos.put(Messages.get().key(Messages.GUI_LOCATION_TYPE_0), m_editValue.getType()); 525 } 526 if (hasMode()) { 527 infos.put(Messages.get().key(Messages.GUI_LOCATION_MODE_0), m_editValue.getMode()); 528 } 529 m_picker.setLocationInfo(infos); 530 m_picker.setPreviewVisible(true); 531 if (!isApiLoaded()) { 532 533 onApiReady(new Command() { 534 535 public void execute() { 536 537 return; 538 } 539 }); 540 } 541 } 542 } 543 544 /** 545 * Checks the current address with the google geocoder to ensure a well formatted address.<p> 546 * Will close the picker popup afterwards.<p> 547 */ 548 private native void ensureFormattedAddress()/*-{ 549 var self = this; 550 var address = self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue.address; 551 if (address != null && address.trim().length > 0) { 552 self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_geocoder 553 .geocode( 554 { 555 'address' : address 556 }, 557 function(results, status) { 558 // check to see if we have at least one valid address 559 if (results 560 && (status == $wnd.google.maps.GeocoderStatus.OK) 561 && results[0].formatted_address) { 562 self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue.address = results[0].formatted_address; 563 } 564 self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::fireChangeAndClose()(); 565 }); 566 } 567 self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::fireChangeAndClose()(); 568 }-*/; 569 570 /** 571 * Fires the value change event and closes the picker popup.<p> 572 */ 573 private void fireChangeAndClose() { 574 575 fireChangeEventOnPicker(false); 576 m_popup.hide(); 577 } 578 579 /** 580 * Returns the Google API key.<p> 581 * 582 * @return the Google API key 583 */ 584 private native String getAPIKey()/*-{ 585 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.apiKey; 586 }-*/; 587 588 /** 589 * Returns the Google API key message.<p> 590 * 591 * @return the Google API key message 592 */ 593 private native String getAPIKeyMessage()/*-{ 594 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.apiKeyMessage; 595 }-*/; 596 597 /** 598 * Returns the value display string.<p> 599 * 600 * @return the value 601 */ 602 private String getDisplayString() { 603 604 return Messages.get().key( 605 Messages.GUI_LOCATION_DISPLAY_3, 606 m_editValue.getAddress(), 607 m_editValue.getLatitudeString(), 608 m_editValue.getLongitudeString()); 609 } 610 611 /** 612 * Evaluates if the address field is configured.<p> 613 * 614 * @return <code>true</code> if the address field is configured 615 */ 616 private native boolean hasAddress()/*-{ 617 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit 618 .indexOf('address') != -1; 619 }-*/; 620 621 /** 622 * Evaluates if the Google API key is configured.<p> 623 * 624 * @return <code>true</code> if the Google API key is configured 625 */ 626 private native boolean hasAPIKey()/*-{ 627 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config != null 628 && this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.apiKey != null; 629 }-*/; 630 631 /** 632 * Evaluates if the lat. lng. fields are configured.<p> 633 * 634 * @return <code>true</code> if the lat. lng. fields are configured 635 */ 636 private native boolean hasLatLng()/*-{ 637 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit 638 .indexOf('coords') != -1; 639 }-*/; 640 641 /** 642 * Evaluates if the map field is configured.<p> 643 * 644 * @return <code>true</code> if the map field is configured 645 */ 646 private native boolean hasMap()/*-{ 647 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit 648 .indexOf('map') != -1; 649 }-*/; 650 651 /** 652 * Evaluates if the mode field is configured.<p> 653 * 654 * @return <code>true</code> if the mode field is configured 655 */ 656 private native boolean hasMode()/*-{ 657 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit 658 .indexOf('mode') != -1; 659 }-*/; 660 661 /** 662 * Evaluates if the size fields are configured.<p> 663 * 664 * @return <code>true</code> if the size fields are configured 665 */ 666 private native boolean hasSize()/*-{ 667 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit 668 .indexOf('size') != -1; 669 }-*/; 670 671 /** 672 * Evaluates if the type field is configured.<p> 673 * 674 * @return <code>true</code> if the type field is configured 675 */ 676 private native boolean hasType()/*-{ 677 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit 678 .indexOf('type') != -1; 679 }-*/; 680 681 /** 682 * Evaluates if the zoom field is configured.<p> 683 * 684 * @return <code>true</code> if the zoom field is configured 685 */ 686 private native boolean hasZoom()/*-{ 687 return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit 688 .indexOf('zoom') != -1; 689 }-*/; 690 691 /** 692 * Adds a CSS style rule to display the localized error message on missing API key.<p> 693 */ 694 private void initDynamicStyle() { 695 696 if (!m_hasInsertedDynamicStyle) { 697 String message = Messages.get().key(Messages.ERR_LOCATION_MISSING_API_KEY_1, "\\a"); 698 message.replace("<br />", "\\\\a"); 699 CmsDomUtil.addDynamicStyleRule( 700 "div.gm-err-content:after, div.mapPreview > div > div:empty:after{ content:'" 701 + message 702 + "' !important; }"); 703 m_hasInsertedDynamicStyle = true; 704 } 705 } 706 707 /** 708 * Initializes the location picker.<p> 709 * 710 * @param callback the callback to execute after initialization 711 */ 712 private void initialize(Runnable callback) { 713 714 if (isApiLoaded()) { 715 initMap(); 716 callback.run(); 717 718 } else { 719 onApiReady(new Command() { 720 721 public void execute() { 722 723 initMap(); 724 callback.run(); 725 } 726 }); 727 } 728 } 729 730 /** 731 * Loads the google maps API and initializes the map afterwards.<p> 732 */ 733 private native void loadApi()/*-{ 734 $wnd.cmsLocationPickerApiReady = function() { 735 @org.opencms.gwt.client.ui.input.location.CmsLocationController::apiReady()(); 736 } 737 var uri = @org.opencms.gwt.client.ui.input.location.CmsLocationController::MAPS_URI; 738 uri += '?' 739 + @org.opencms.gwt.client.ui.input.location.CmsLocationController::MAPS_MAIN_PARAM 740 + '&' 741 + @org.opencms.gwt.client.ui.input.location.CmsLocationController::MAPS_PLACES_PARAM; 742 if (this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::hasAPIKey()()) { 743 uri += '&key=' 744 + this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::getAPIKey()(); 745 if ($wnd.console) { 746 $wnd.console 747 .log(this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::getAPIKeyMessage()()); 748 } 749 } else if ($wnd.console) { 750 $wnd.console.log("No Google API key available"); 751 } 752 uri += '&callback=cmsLocationPickerApiReady'; 753 754 var script = $wnd.document.createElement('script'); 755 script.src = uri; 756 $wnd.document.body.appendChild(script); 757 }-*/; 758 759 /** 760 * Adds a callback to be executed once the API is ready. Will be executed right away if the API is already loaded.<p> 761 * 762 * @param callback the callback 763 */ 764 private void onApiReady(Command callback) { 765 766 if (isApiLoaded()) { 767 callback.execute(); 768 } else { 769 onApiReady.add(callback); 770 if (!loadingApi) { 771 loadingApi = true; 772 loadApi(); 773 } 774 } 775 } 776 777 /** 778 * Parses the configuration string.<p> 779 * 780 * @param configuration the configuration 781 */ 782 private native void parseConfig(String configuration)/*-{ 783 this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config = JSON 784 .parse(configuration); 785 }-*/; 786 787 /** 788 * Sets all editable fields visible.<p> 789 */ 790 private void setFieldVisibility() { 791 792 m_popupContent.setMapVisible(hasMap()); 793 m_popupContent.setAddressVisible(hasAddress()); 794 m_popupContent.setLatLngVisible(hasLatLng()); 795 m_popupContent.setSizeVisible(hasSize()); 796 m_popupContent.setTypeVisible(hasType()); 797 m_popupContent.setModeVisible(hasMode()); 798 m_popupContent.setZoomVisible(hasZoom()); 799 } 800 801 /** 802 * Sets the position values and updates the map view.<p> 803 * 804 * @param latitude the latitude 805 * @param longitude the longitude 806 * @param updateMap <code>true</code> to update the map 807 * @param updateAddress <code>true</code> to update the address from the new position data 808 */ 809 private void setPosition(float latitude, float longitude, boolean updateMap, boolean updateAddress) { 810 811 m_editValue.setLatitude(latitude); 812 m_editValue.setLongitude(longitude); 813 m_popupContent.displayValues(m_editValue); 814 if (updateMap) { 815 updateMarkerPosition(); 816 } 817 if (updateAddress) { 818 updateAddress(); 819 } 820 } 821 822 /** 823 * Updates the address according to the current position data.<p> 824 */ 825 private native void updateAddress()/*-{ 826 var self = this; 827 var pos = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::getCurrentPosition()(); 828 // try to evaluate the address from the current position 829 this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_geocoder 830 .geocode( 831 { 832 'latLng' : pos 833 }, 834 function(results, status) { 835 var address = ""; 836 // check that everything is ok 837 if (status == $wnd.google.maps.GeocoderStatus.OK 838 && results[0] 839 && results[0].formatted_address) { 840 // set the new address 841 address = results[0].formatted_address; 842 } 843 if (address != self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue.address) { 844 self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue.address = address; 845 self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::updateForm()(); 846 } 847 }); 848 }-*/; 849 850 /** 851 * Displays the current location value within the popup form.<p> 852 */ 853 private void updateForm() { 854 855 m_popupContent.displayValues(m_editValue); 856 } 857 858 /** 859 * Updates the marker position according to the current location value.<p> 860 */ 861 private native void updateMarkerPosition()/*-{ 862 var map = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_map; 863 var pos = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::getCurrentPosition()(); 864 var marker = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_marker; 865 if (marker == null) { 866 try { 867 var marker = new $wnd.google.maps.Marker({ 868 position : pos, 869 map : map, 870 draggable : true 871 }); 872 this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_marker = marker; 873 var self = this; 874 // handle marker dnd 875 $wnd.google.maps.event 876 .addListener( 877 marker, 878 "dragend", 879 function() { 880 var lat = marker.getPosition().lat(); 881 var lng = marker.getPosition().lng(); 882 self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::setPosition(FFZZ)(lat,lng,false,true); 883 }); 884 } catch (e) { 885 $wnd.alert(e.message); 886 } 887 } else { 888 marker.setPosition(pos); 889 } 890 map.panTo(pos); 891 map.setCenter(pos); 892 }-*/; 893 894}