text: /**
   * @license
   * Visual Blocks Editor
   *
   * Copyright 2019 Google Inc.
   * https://developers.google.com/blockly/
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *   http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  /**
   * @fileoverview Utilities for element styles.
   * These methods are not specific to Blockly, and could be factored out into
   * a JavaScript framework such as Closure.
   * @author samelh@google.com (Sam El-Husseini)
   */
  'use strict';
  
  /**
   * @name Blockly.utils.style
   * @namespace
   */
  goog.provide('Blockly.utils.style');
  
  goog.require('Blockly.utils.Coordinate');
  goog.require('Blockly.utils.Size');
  
  
  /**
   * Gets the height and width of an element.
   * Similar to Closure's goog.style.getSize.
   * @param {Element} element Element to get size of.
   * @return {!Blockly.utils.Size} Object with width/height properties.
   */
  Blockly.utils.style.getSize = function(element) {
    if (Blockly.utils.style.getStyle_(element, 'display') != 'none') {
      var offsetWidth = /** @type {!HTMLElement} */ (element).offsetWidth;
      var offsetHeight = /** @type {!HTMLElement} */ (element).offsetHeight;
      return new Blockly.utils.Size(offsetWidth, offsetHeight);
    }
  
    // Evaluate size with a temporary element.
    var style = element.style;
    var originalDisplay = style.display;
    var originalVisibility = style.visibility;
    var originalPosition = style.position;
  
    style.visibility = 'hidden';
    style.position = 'absolute';
    style.display = 'inline';
  
    var offsetWidth = /** @type {!HTMLElement} */ (element).offsetWidth;
    var offsetHeight = /** @type {!HTMLElement} */ (element).offsetHeight;
  
    style.display = originalDisplay;
    style.position = originalPosition;
    style.visibility = originalVisibility;
  
    return new Blockly.utils.Size(offsetWidth, offsetHeight);
  };
  
  /**
   * Cross-browser pseudo get computed style. It returns the computed style where
   * available. If not available it tries the cascaded style value (IE
   * currentStyle) and in worst case the inline style value.  It shouldn't be
   * called directly, see http://wiki/Main/ComputedStyleVsCascadedStyle for
   * discussion.
   *
   * Copied from Closure's goog.ui.style
   *
   * @param {Element} element Element to get style of.
   * @param {string} style Property to get (must be camelCase, not css-style.).
   * @return {string} Style value.
   * @private
   */
  Blockly.utils.style.getStyle_ = function(element, style) {
    return Blockly.utils.style.getComputedStyle(element, style) ||
        Blockly.utils.style.getCascadedStyle(element, style) ||
        (element.style && element.style[style]);
  };
  
  /**
   * Retrieves a computed style value of a node. It returns empty string if the
   * value cannot be computed (which will be the case in Internet Explorer) or
   * "none" if the property requested is an SVG one and it has not been
   * explicitly set (firefox and webkit).
   *
   * Copied from Closure's goog.ui.style
   *
   * @param {Element} element Element to get style of.
   * @param {string} property Property to get (camel-case).
   * @return {string} Style value.
   */
  Blockly.utils.style.getComputedStyle = function(element, property) {
    if (document.defaultView && document.defaultView.getComputedStyle) {
      var styles = document.defaultView.getComputedStyle(element, null);
      if (styles) {
        // element.style[..] is undefined for browser specific styles
        // as 'filter'.
        return styles[property] || styles.getPropertyValue(property) || '';
      }
    }
  
    return '';
  };
  
  /**
   * Gets the cascaded style value of a node, or null if the value cannot be
   * computed (only Internet Explorer can do this).
   *
   * Copied from Closure's goog.ui.style
   *
   * @param {Element} element Element to get style of.
   * @param {string} style Property to get (camel-case).
   * @return {string} Style value.
   */
  Blockly.utils.style.getCascadedStyle = function(element, style) {
    return /** @type {string} */ (
        element.currentStyle ? element.currentStyle[style] : null);
  };
  
  /**
   * Returns a Coordinate object relative to the top-left of the HTML document.
   * Similar to Closure's goog.style.getPageOffset.
   * @param {Element} el Element to get the page offset for.
   * @return {!Blockly.utils.Coordinate} The page offset.
   */
  Blockly.utils.style.getPageOffset = function(el) {
    var pos = new Blockly.utils.Coordinate(0, 0);
    var box = el.getBoundingClientRect();
    var documentElement = document.documentElement;
    // Must add the scroll coordinates in to get the absolute page offset
    // of element since getBoundingClientRect returns relative coordinates to
    // the viewport.
    var scrollCoord = new Blockly.utils.Coordinate(
        window.pageXOffset || documentElement.scrollLeft,
        window.pageYOffset || documentElement.scrollTop);
    pos.x = box.left + scrollCoord.x;
    pos.y = box.top + scrollCoord.y;
  
    return pos;
  };
  
  /**
   * Calculates the viewport coordinates relative to the document.
   * Similar to Closure's goog.style.getViewportPageOffset.
   * @return {!Blockly.utils.Coordinate} The page offset of the viewport.
   */
  Blockly.utils.style.getViewportPageOffset = function() {
    var body = document.body;
    var documentElement = document.documentElement;
    var scrollLeft = body.scrollLeft || documentElement.scrollLeft;
    var scrollTop = body.scrollTop || documentElement.scrollTop;
    return new Blockly.utils.Coordinate(scrollLeft, scrollTop);
  };
  