text: import buildModuleUrl from "../../Core/buildModuleUrl.js";
  import Check from "../../Core/Check.js";
  import Color from "../../Core/Color.js";
  import defined from "../../Core/defined.js";
  import destroyObject from "../../Core/destroyObject.js";
  import knockout from "../../ThirdParty/knockout.js";
  import getElement from "../getElement.js";
  import subscribeAndEvaluate from "../subscribeAndEvaluate.js";
  import InfoBoxViewModel from "./InfoBoxViewModel.js";
  
  /**
   * A widget for displaying information or a description.
   *
   * @alias InfoBox
   * @constructor
   *
   * @param {Element|String} container The DOM element or ID that will contain the widget.
   *
   * @exception {DeveloperError} Element with id "container" does not exist in the document.
   */
  function InfoBox(container) {
    //>>includeStart('debug', pragmas.debug);
    Check.defined("container", container);
    //>>includeEnd('debug')
  
    container = getElement(container);
  
    const infoElement = document.createElement("div");
    infoElement.className = "cesium-infoBox";
    infoElement.setAttribute(
      "data-bind",
      '\
  css: { "cesium-infoBox-visible" : showInfo, "cesium-infoBox-bodyless" : _bodyless }'
    );
    container.appendChild(infoElement);
  
    const titleElement = document.createElement("div");
    titleElement.className = "cesium-infoBox-title";
    titleElement.setAttribute("data-bind", "text: titleText");
    infoElement.appendChild(titleElement);
  
    const cameraElement = document.createElement("button");
    cameraElement.type = "button";
    cameraElement.className = "cesium-button cesium-infoBox-camera";
    cameraElement.setAttribute(
      "data-bind",
      '\
  attr: { title: "Focus camera on object" },\
  click: function () { cameraClicked.raiseEvent(this); },\
  enable: enableCamera,\
  cesiumSvgPath: { path: cameraIconPath, width: 32, height: 32 }'
    );
    infoElement.appendChild(cameraElement);
  
    const closeElement = document.createElement("button");
    closeElement.type = "button";
    closeElement.className = "cesium-infoBox-close";
    closeElement.setAttribute(
      "data-bind",
      "\
  click: function () { closeClicked.raiseEvent(this); }"
    );
    closeElement.innerHTML = "&times;";
    infoElement.appendChild(closeElement);
  
    const frame = document.createElement("iframe");
    frame.className = "cesium-infoBox-iframe";
    frame.setAttribute("sandbox", "allow-same-origin allow-popups allow-forms"); //allow-pointer-lock allow-scripts allow-top-navigation
    frame.setAttribute(
      "data-bind",
      "style : { maxHeight : maxHeightOffset(40) }"
    );
    frame.setAttribute("allowfullscreen", true);
    infoElement.appendChild(frame);
  
    const viewModel = new InfoBoxViewModel();
    knockout.applyBindings(viewModel, infoElement);
  
    this._container = container;
    this._element = infoElement;
    this._frame = frame;
    this._viewModel = viewModel;
    this._descriptionSubscription = undefined;
  
    const that = this;
    //We can't actually add anything into the frame until the load event is fired
    frame.addEventListener("load", function () {
      const frameDocument = frame.contentDocument;
  
      //We inject default css into the content iframe,
      //end users can remove it or add their own via the exposed frame property.
      const cssLink = frameDocument.createElement("link");
      cssLink.href = buildModuleUrl("Widgets/InfoBox/InfoBoxDescription.css");
      cssLink.rel = "stylesheet";
      cssLink.type = "text/css";
  
      //div to use for description content.
      const frameContent = frameDocument.createElement("div");
      frameContent.className = "cesium-infoBox-description";
  
      frameDocument.head.appendChild(cssLink);
      frameDocument.body.appendChild(frameContent);
  
      //We manually subscribe to the description event rather than through a binding for two reasons.
      //1. It's an easy way to ensure order of operation so that we can adjust the height.
      //2. Knockout does not bind to elements inside of an iFrame, so we would have to apply a second binding
      //   model anyway.
      that._descriptionSubscription = subscribeAndEvaluate(
        viewModel,
        "description",
        function (value) {
          // Set the frame to small height, force vertical scroll bar to appear, and text to wrap accordingly.
          frame.style.height = "5px";
          frameContent.innerHTML = value;
  
          //If the snippet is a single element, then use its background
          //color for the body of the InfoBox. This makes the padding match
          //the content and produces much nicer results.
          let background = null;
          const firstElementChild = frameContent.firstElementChild;
          if (
            firstElementChild !== null &&
            frameContent.childNodes.length === 1
          ) {
            const style = window.getComputedStyle(firstElementChild);
            if (style !== null) {
              const backgroundColor = style["background-color"];
              const color = Color.fromCssColorString(backgroundColor);
              if (defined(color) && color.alpha !== 0) {
                background = style["background-color"];
              }
            }
          }
          infoElement.style["background-color"] = background;
  
          // Measure and set the new custom height, based on text wrapped above.
          const height = frameContent.getBoundingClientRect().height;
          frame.style.height = `${height}px`;
        }
      );
    });
  
    //Chrome does not send the load event unless we explicitly set a src
    frame.setAttribute("src", "about:blank");
  }
  
  Object.defineProperties(InfoBox.prototype, {
    /**
     * Gets the parent container.
     * @memberof InfoBox.prototype
     *
     * @type {Element}
     */
    container: {
      get: function () {
        return this._container;
      },
    },
  
    /**
     * Gets the view model.
     * @memberof InfoBox.prototype
     *
     * @type {InfoBoxViewModel}
     */
    viewModel: {
      get: function () {
        return this._viewModel;
      },
    },
  
    /**
     * Gets the iframe used to display the description.
     * @memberof InfoBox.prototype
     *
     * @type {HTMLIFrameElement}
     */
    frame: {
      get: function () {
        return this._frame;
      },
    },
  });
  
  /**
   * @returns {Boolean} true if the object has been destroyed, false otherwise.
   */
  InfoBox.prototype.isDestroyed = function () {
    return false;
  };
  
  /**
   * Destroys the widget.  Should be called if permanently
   * removing the widget from layout.
   */
  InfoBox.prototype.destroy = function () {
    const container = this._container;
    knockout.cleanNode(this._element);
    container.removeChild(this._element);
  
    if (defined(this._descriptionSubscription)) {
      this._descriptionSubscription.dispose();
    }
  
    return destroyObject(this);
  };
  export default InfoBox;
  