| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 | import defined from "../../Core/defined.js";import destroyObject from "../../Core/destroyObject.js";import DeveloperError from "../../Core/DeveloperError.js";import FeatureDetection from "../../Core/FeatureDetection.js";import knockout from "../../ThirdParty/knockout.js";import getElement from "../getElement.js";import GeocoderViewModel from "./GeocoderViewModel.js";const startSearchPath =  "M29.772,26.433l-7.126-7.126c0.96-1.583,1.523-3.435,1.524-5.421C24.169,8.093,19.478,3.401,13.688,3.399C7.897,3.401,3.204,8.093,3.204,13.885c0,5.789,4.693,10.481,10.484,10.481c1.987,0,3.839-0.563,5.422-1.523l7.128,7.127L29.772,26.433zM7.203,13.885c0.006-3.582,2.903-6.478,6.484-6.486c3.579,0.008,6.478,2.904,6.484,6.486c-0.007,3.58-2.905,6.476-6.484,6.484C10.106,20.361,7.209,17.465,7.203,13.885z";const stopSearchPath =  "M24.778,21.419 19.276,15.917 24.777,10.415 21.949,7.585 16.447,13.087 10.945,7.585 8.117,10.415 13.618,15.917 8.116,21.419 10.946,24.248 16.447,18.746 21.948,24.248z";/** * A widget for finding addresses and landmarks, and flying the camera to them.  Geocoding is * performed using {@link https://cesium.com/cesium-ion/|Cesium ion}. * * @alias Geocoder * @constructor * * @param {Object} options Object with the following properties: * @param {Element|String} options.container The DOM element or ID that will contain the widget. * @param {Scene} options.scene The Scene instance to use. * @param {GeocoderService[]} [options.geocoderServices] The geocoder services to be used * @param {Boolean} [options.autoComplete = true] True if the geocoder should query as the user types to autocomplete * @param {Number} [options.flightDuration=1.5] The duration of the camera flight to an entered location, in seconds. * @param {Geocoder.DestinationFoundFunction} [options.destinationFound=GeocoderViewModel.flyToDestination] A callback function that is called after a successful geocode.  If not supplied, the default behavior is to fly the camera to the result destination. */function Geocoder(options) {  //>>includeStart('debug', pragmas.debug);  if (!defined(options) || !defined(options.container)) {    throw new DeveloperError("options.container is required.");  }  if (!defined(options.scene)) {    throw new DeveloperError("options.scene is required.");  }  //>>includeEnd('debug');  const container = getElement(options.container);  const viewModel = new GeocoderViewModel(options);  viewModel._startSearchPath = startSearchPath;  viewModel._stopSearchPath = stopSearchPath;  const form = document.createElement("form");  form.setAttribute("data-bind", "submit: search");  const textBox = document.createElement("input");  textBox.type = "search";  textBox.className = "cesium-geocoder-input";  textBox.setAttribute("placeholder", "Enter an address or landmark...");  textBox.setAttribute(    "data-bind",    '\textInput: searchText,\disable: isSearchInProgress,\event: { keyup: handleKeyUp, keydown: handleKeyDown, mouseover: deselectSuggestion },\css: { "cesium-geocoder-input-wide" : keepExpanded || searchText.length > 0 },\hasFocus: _focusTextbox'  );  this._onTextBoxFocus = function () {    // as of 2016-10-19, setTimeout is required to ensure that the    // text is focused on Safari 10    setTimeout(function () {      textBox.select();    }, 0);  };  textBox.addEventListener("focus", this._onTextBoxFocus, false);  form.appendChild(textBox);  this._textBox = textBox;  const searchButton = document.createElement("span");  searchButton.className = "cesium-geocoder-searchButton";  searchButton.setAttribute(    "data-bind",    "\click: search,\cesiumSvgPath: { path: isSearchInProgress ? _stopSearchPath : _startSearchPath, width: 32, height: 32 }"  );  form.appendChild(searchButton);  container.appendChild(form);  const searchSuggestionsContainer = document.createElement("div");  searchSuggestionsContainer.className = "search-results";  searchSuggestionsContainer.setAttribute(    "data-bind",    "visible: _suggestionsVisible"  );  const suggestionsList = document.createElement("ul");  suggestionsList.setAttribute("data-bind", "foreach: _suggestions");  const suggestions = document.createElement("li");  suggestionsList.appendChild(suggestions);  suggestions.setAttribute(    "data-bind",    "text: $data.displayName, \click: $parent.activateSuggestion, \event: { mouseover: $parent.handleMouseover}, \css: { active: $data === $parent._selectedSuggestion }"  );  searchSuggestionsContainer.appendChild(suggestionsList);  container.appendChild(searchSuggestionsContainer);  knockout.applyBindings(viewModel, form);  knockout.applyBindings(viewModel, searchSuggestionsContainer);  this._container = container;  this._searchSuggestionsContainer = searchSuggestionsContainer;  this._viewModel = viewModel;  this._form = form;  this._onInputBegin = function (e) {    // e.target will not be correct if we are inside of the Shadow DOM    // and contains will always fail. To retrieve the correct target,    // we need to access the first element of the composedPath.    // This allows us to use shadow DOM if it exists and fall    // back to legacy behavior if its not being used.    let target = e.target;    if (typeof e.composedPath === "function") {      target = e.composedPath()[0];    }    if (!container.contains(target)) {      viewModel._focusTextbox = false;      viewModel.hideSuggestions();    }  };  this._onInputEnd = function (e) {    viewModel._focusTextbox = true;    viewModel.showSuggestions();  };  //We subscribe to both begin and end events in order to give the text box  //focus no matter where on the widget is clicked.  if (FeatureDetection.supportsPointerEvents()) {    document.addEventListener("pointerdown", this._onInputBegin, true);    container.addEventListener("pointerup", this._onInputEnd, true);    container.addEventListener("pointercancel", this._onInputEnd, true);  } else {    document.addEventListener("mousedown", this._onInputBegin, true);    container.addEventListener("mouseup", this._onInputEnd, true);    document.addEventListener("touchstart", this._onInputBegin, true);    container.addEventListener("touchend", this._onInputEnd, true);    container.addEventListener("touchcancel", this._onInputEnd, true);  }}Object.defineProperties(Geocoder.prototype, {  /**   * Gets the parent container.   * @memberof Geocoder.prototype   *   * @type {Element}   */  container: {    get: function () {      return this._container;    },  },  /**   * Gets the parent container.   * @memberof Geocoder.prototype   *   * @type {Element}   */  searchSuggestionsContainer: {    get: function () {      return this._searchSuggestionsContainer;    },  },  /**   * Gets the view model.   * @memberof Geocoder.prototype   *   * @type {GeocoderViewModel}   */  viewModel: {    get: function () {      return this._viewModel;    },  },});/** * @returns {Boolean} true if the object has been destroyed, false otherwise. */Geocoder.prototype.isDestroyed = function () {  return false;};/** * Destroys the widget.  Should be called if permanently * removing the widget from layout. */Geocoder.prototype.destroy = function () {  const container = this._container;  if (FeatureDetection.supportsPointerEvents()) {    document.removeEventListener("pointerdown", this._onInputBegin, true);    container.removeEventListener("pointerup", this._onInputEnd, true);  } else {    document.removeEventListener("mousedown", this._onInputBegin, true);    container.removeEventListener("mouseup", this._onInputEnd, true);    document.removeEventListener("touchstart", this._onInputBegin, true);    container.removeEventListener("touchend", this._onInputEnd, true);  }  this._viewModel.destroy();  knockout.cleanNode(this._form);  knockout.cleanNode(this._searchSuggestionsContainer);  container.removeChild(this._form);  container.removeChild(this._searchSuggestionsContainer);  this._textBox.removeEventListener("focus", this._onTextBoxFocus, false);  return destroyObject(this);};/** * A function that handles the result of a successful geocode. * @callback Geocoder.DestinationFoundFunction * @param {GeocoderViewModel} viewModel The view model. * @param {Cartesian3|Rectangle} destination The destination result of the geocode. */export default Geocoder;
 |