function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }

function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }

function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }

function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }

function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }

function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }

function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }

function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }

function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }

function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }

function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

/**
 * 
 * @file Content Preview Component
 * @author Box
 */
import 'regenerator-runtime/runtime';
import * as React from 'react';
import classNames from 'classnames';
import uniqueid from 'lodash/uniqueId';
import throttle from 'lodash/throttle';
import cloneDeep from 'lodash/cloneDeep';
import omit from 'lodash/omit';
import getProp from 'lodash/get';
import flow from 'lodash/flow';
import noop from 'lodash/noop';
import setProp from 'lodash/set';
import Measure from 'react-measure';
import { withRouter } from 'react-router-dom';
import { decode } from '../../utils/keys';
import makeResponsive from '../common/makeResponsive';
import { withNavRouter } from '../common/nav-router';
import Internationalize from '../common/Internationalize';
import AsyncLoad from '../common/async-load';
import TokenService from '../../utils/TokenService';
import { isInputElement, focus } from '../../utils/dom';
import { getTypedFileId } from '../../utils/file';
import { withErrorBoundary } from '../common/error-boundary';
import { withLogger } from '../common/logger';
import { PREVIEW_FIELDS_TO_FETCH } from '../../utils/fields';
import { mark } from '../../utils/performance';
import { withFeatureProvider } from '../common/feature-checking';
import { EVENT_JS_READY } from '../common/logger/constants';
import ReloadNotification from './ReloadNotification';
import API from '../../api';
import PreviewHeader from './preview-header';
import PreviewMask from './PreviewMask';
import PreviewNavigation from './PreviewNavigation';
import { withAnnotations, WithAnnotationsProps, withAnnotatorContext, WithAnnotatorContextProps } from '../common/annotator-context';
import { DEFAULT_HOSTNAME_API, DEFAULT_HOSTNAME_APP, DEFAULT_HOSTNAME_STATIC, DEFAULT_PREVIEW_VERSION, DEFAULT_LOCALE, DEFAULT_PATH_STATIC_PREVIEW, CLIENT_NAME_CONTENT_PREVIEW, ORIGIN_PREVIEW, ORIGIN_CONTENT_PREVIEW, ERROR_CODE_UNKNOWN } from '../../constants';
import '../common/fonts.scss';
import '../common/base.scss';
import './ContentPreview.scss';
var startAtTypes = {
  page: 'pages'
};
var InvalidIdError = new Error('Invalid id for Preview!');
var PREVIEW_LOAD_METRIC_EVENT = 'load';
var MARK_NAME_JS_READY = "".concat(ORIGIN_CONTENT_PREVIEW, "_").concat(EVENT_JS_READY);
mark(MARK_NAME_JS_READY);
var LoadableSidebar = AsyncLoad({
  loader: function loader() {
    return import(
    /* webpackMode: "lazy", webpackChunkName: "content-sidebar" */
    '../content-sidebar');
  }
});

var ContentPreview = /*#__PURE__*/function (_React$PureComponent) {
  _inherits(ContentPreview, _React$PureComponent);

  var _super = _createSuper(ContentPreview);

  // Defines a generic type for ContentSidebar, since an import would interfere with code splitting

  /**
   * [constructor]
   *
   * @return {ContentPreview}
   */
  function ContentPreview(props) {
    var _this;

    _classCallCheck(this, ContentPreview);

    _this = _super.call(this, props);

    _defineProperty(_assertThisInitialized(_this), "contentSidebar", /*#__PURE__*/React.createRef());

    _defineProperty(_assertThisInitialized(_this), "initialState", {
      canPrint: false,
      error: undefined,
      isLoading: true,
      isReloadNotificationVisible: false,
      isThumbnailSidebarOpen: false
    });

    _defineProperty(_assertThisInitialized(_this), "onPreviewError", function (_ref) {
      var error = _ref.error,
          rest = _objectWithoutProperties(_ref, ["error"]);

      var _error$code = error.code,
          code = _error$code === void 0 ? ERROR_CODE_UNKNOWN : _error$code;
      var onError = _this.props.onError; // In case of error, there should be no thumbnail sidebar to account for

      _this.setState({
        isLoading: false,
        isThumbnailSidebarOpen: false
      });

      onError(error, code, _objectSpread(_objectSpread({}, rest), {}, {
        error: error
      }), ORIGIN_PREVIEW);
    });

    _defineProperty(_assertThisInitialized(_this), "onPreviewMetric", function (previewMetrics) {
      var logger = _this.props.logger;
      var event_name = previewMetrics.event_name;

      var metrics = _objectSpread({}, previewMetrics); // We need to add in the total file fetch time to the file_info_time and value (total)
      // as preview does not do the files call


      if (event_name === PREVIEW_LOAD_METRIC_EVENT) {
        var totalFetchFileTime = _this.getTotalFileFetchTime();

        var totalTime = (previewMetrics.value || 0) + totalFetchFileTime; // If an unnatural load time occurs or is invalid, don't log a load event

        if (!totalTime) {
          return;
        }

        metrics = _objectSpread(_objectSpread({}, previewMetrics), {}, {
          file_info_time: totalFetchFileTime,
          value: totalTime
        });
      }

      logger.onPreviewMetric(metrics);
    });

    _defineProperty(_assertThisInitialized(_this), "onPreviewLoad", function (data) {
      var _this$props = _this.props,
          onLoad = _this$props.onLoad,
          collection = _this$props.collection;

      var currentIndex = _this.getFileIndex();

      var filesToPrefetch = collection.slice(currentIndex + 1, currentIndex + 5);
      var previewTimeMetrics = getProp(data, 'metrics.time');
      var loadData = data;

      if (previewTimeMetrics) {
        var totalPreviewMetrics = _this.addFetchFileTimeToPreviewMetrics(previewTimeMetrics);

        loadData = _objectSpread(_objectSpread({}, loadData), {}, {
          metrics: _objectSpread(_objectSpread({}, loadData.metrics), {}, {
            time: totalPreviewMetrics
          })
        });
      }

      onLoad(loadData);

      _this.setState({
        isLoading: false
      });

      _this.focusPreview();

      if (_this.preview && filesToPrefetch.length) {
        _this.prefetch(filesToPrefetch);
      }

      _this.handleCanPrint();
    });

    _defineProperty(_assertThisInitialized(_this), "loadPreview", /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
      var _this$props2, _this$props2$annotato, activeAnnotationId, enableThumbnailsSidebar, fileOptions, onAnnotatorEvent, onAnnotator, showAnnotationsControls, tokenOrTokenFunction, rest, _this$state, file, selectedVersion, startAt, fileId, fileOpts, token, previewOptions, Preview;

      return regeneratorRuntime.wrap(function _callee$(_context) {
        while (1) {
          switch (_context.prev = _context.next) {
            case 0:
              _this$props2 = _this.props, _this$props2$annotato = _this$props2.annotatorState;
              _this$props2$annotato = _this$props2$annotato === void 0 ? {} : _this$props2$annotato;
              activeAnnotationId = _this$props2$annotato.activeAnnotationId, enableThumbnailsSidebar = _this$props2.enableThumbnailsSidebar, fileOptions = _this$props2.fileOptions, onAnnotatorEvent = _this$props2.onAnnotatorEvent, onAnnotator = _this$props2.onAnnotator, showAnnotationsControls = _this$props2.showAnnotationsControls, tokenOrTokenFunction = _this$props2.token, rest = _objectWithoutProperties(_this$props2, ["annotatorState", "enableThumbnailsSidebar", "fileOptions", "onAnnotatorEvent", "onAnnotator", "showAnnotationsControls", "token"]);
              _this$state = _this.state, file = _this$state.file, selectedVersion = _this$state.selectedVersion, startAt = _this$state.startAt;

              if (!(!_this.isPreviewLibraryLoaded() || !file || !tokenOrTokenFunction)) {
                _context.next = 6;
                break;
              }

              return _context.abrupt("return");

            case 6:
              fileId = _this.getFileId(file);

              if (!(fileId !== _this.state.currentFileId)) {
                _context.next = 9;
                break;
              }

              return _context.abrupt("return");

            case 9:
              fileOpts = _objectSpread({}, fileOptions);

              token = function token(typedId) {
                return TokenService.getReadTokens(typedId, tokenOrTokenFunction);
              };

              if (selectedVersion) {
                setProp(fileOpts, [fileId, 'fileVersionId'], selectedVersion.id);
                setProp(fileOpts, [fileId, 'currentFileVersionId'], getProp(file, 'file_version.id'));
              }

              if (activeAnnotationId) {
                setProp(fileOpts, [fileId, 'annotations', 'activeId'], activeAnnotationId);
              }

              if (startAt) {
                setProp(fileOpts, [fileId, 'startAt'], startAt);
              }

              previewOptions = {
                container: "#".concat(_this.id, " .bcpr-content"),
                enableThumbnailsSidebar: enableThumbnailsSidebar,
                fileOptions: fileOpts,
                header: 'none',
                headerElement: "#".concat(_this.id, " .bcpr-PreviewHeader"),
                showAnnotations: _this.canViewAnnotations(),
                showAnnotationsControls: showAnnotationsControls,
                showDownload: _this.canDownload(),
                showLoading: false,
                showProgress: false,
                skipServerUpdate: true,
                useHotkeys: false
              };
              Preview = global.Box.Preview;
              _this.preview = new Preview();

              _this.preview.addListener('load', _this.onPreviewLoad);

              _this.preview.addListener('preview_error', _this.onPreviewError);

              _this.preview.addListener('preview_metric', _this.onPreviewMetric);

              _this.preview.addListener('thumbnailsOpen', function () {
                return _this.setState({
                  isThumbnailSidebarOpen: true
                });
              });

              _this.preview.addListener('thumbnailsClose', function () {
                return _this.setState({
                  isThumbnailSidebarOpen: false
                });
              });

              if (showAnnotationsControls) {
                _this.preview.addListener('annotator_create', onAnnotator);
              }

              _this.preview.updateFileCache([file]);

              _this.preview.show(file.id, token, _objectSpread(_objectSpread({}, previewOptions), omit(rest, Object.keys(previewOptions))));

            case 25:
            case "end":
              return _context.stop();
          }
        }
      }, _callee);
    })));

    _defineProperty(_assertThisInitialized(_this), "loadFileFromStage", function () {
      if (_this.stagedFile) {
        _this.setState(_objectSpread(_objectSpread({}, _this.initialState), {}, {
          file: _this.stagedFile
        }), function () {
          _this.stagedFile = undefined;
        });
      }
    });

    _defineProperty(_assertThisInitialized(_this), "closeReloadNotification", function () {
      _this.setState({
        isReloadNotificationVisible: false
      });
    });

    _defineProperty(_assertThisInitialized(_this), "onResize", function () {
      if (_this.preview && _this.preview.getCurrentViewer()) {
        _this.preview.resize();
      }
    });

    _defineProperty(_assertThisInitialized(_this), "fetchFileSuccessCallback", function (file) {
      _this.fetchFileEndTime = performance.now();
      var currentFile = _this.state.file;
      var isExistingFile = currentFile ? currentFile.id === file.id : false;
      var isWatermarked = getProp(file, 'watermark_info.is_watermarked', false); // If the file is watermarked or if its a new file, then update the state
      // In this case preview should reload without prompting the user

      if (isWatermarked || !isExistingFile) {
        _this.setState(_objectSpread(_objectSpread({}, _this.initialState), {}, {
          file: file
        })); // $FlowFixMe file version and sha1 should exist at this point

      } else if (currentFile.file_version.sha1 !== file.file_version.sha1) {
        // If we are already prevewing the file that got updated then show the
        // user a notification to reload the file only if its sha1 changed
        _this.stagedFile = file;

        _this.setState(_objectSpread(_objectSpread({}, _this.initialState), {}, {
          isReloadNotificationVisible: true
        }));
      }
    });

    _defineProperty(_assertThisInitialized(_this), "fetchFileErrorCallback", function (fileError, code) {
      var onError = _this.props.onError;
      var errorCode = fileError.code || code;
      var error = {
        code: errorCode,
        message: fileError.message
      };

      _this.setState({
        error: error,
        file: undefined
      });

      onError(fileError, errorCode, {
        error: fileError
      });
    });

    _defineProperty(_assertThisInitialized(_this), "getPreview", function () {
      var file = _this.state.file;

      if (!_this.preview || !file) {
        return null;
      }

      return _this.preview;
    });

    _defineProperty(_assertThisInitialized(_this), "getViewer", function () {
      var preview = _this.getPreview();

      var viewer = preview ? preview.getCurrentViewer() : null;
      return viewer && viewer.isLoaded() && !viewer.isDestroyed() ? viewer : null;
    });

    _defineProperty(_assertThisInitialized(_this), "navigateLeft", function () {
      var currentIndex = _this.getFileIndex();

      var newIndex = currentIndex === 0 ? 0 : currentIndex - 1;

      if (newIndex !== currentIndex) {
        _this.navigateToIndex(newIndex);
      }
    });

    _defineProperty(_assertThisInitialized(_this), "navigateRight", function () {
      var collection = _this.props.collection;

      var currentIndex = _this.getFileIndex();

      var newIndex = currentIndex === collection.length - 1 ? collection.length - 1 : currentIndex + 1;

      if (newIndex !== currentIndex) {
        _this.navigateToIndex(newIndex);
      }
    });

    _defineProperty(_assertThisInitialized(_this), "download", function () {
      var onDownload = _this.props.onDownload;
      var file = _this.state.file;

      if (_this.preview) {
        _this.preview.download();

        onDownload(cloneDeep(file));
      }
    });

    _defineProperty(_assertThisInitialized(_this), "print", function () {
      if (_this.preview) {
        _this.preview.print();
      }
    });

    _defineProperty(_assertThisInitialized(_this), "onMouseMove", throttle(function () {
      var viewer = _this.getViewer();

      var isPreviewing = !!viewer;
      var CLASS_NAVIGATION_VISIBILITY = 'bcpr-nav-is-visible';
      clearTimeout(_this.mouseMoveTimeoutID);

      if (!_this.previewContainer) {
        return;
      } // Always assume that navigation arrows will be hidden


      _this.previewContainer.classList.remove(CLASS_NAVIGATION_VISIBILITY); // Only show it if either we aren't previewing or if we are then the viewer
      // is not blocking the show. If we are previewing then the viewer may choose
      // to not allow navigation arrows. This is mostly useful for videos since the
      // navigation arrows may interfere with the settings menu inside video player.


      if (_this.previewContainer && (!isPreviewing || viewer.allowNavigationArrows())) {
        _this.previewContainer.classList.add(CLASS_NAVIGATION_VISIBILITY);
      }

      _this.mouseMoveTimeoutID = setTimeout(function () {
        if (_this.previewContainer) {
          _this.previewContainer.classList.remove(CLASS_NAVIGATION_VISIBILITY);
        }
      }, 1500);
    }, 1000));

    _defineProperty(_assertThisInitialized(_this), "onKeyDown", function (event) {
      var useHotkeys = _this.props.useHotkeys;

      if (!useHotkeys) {
        return;
      }

      var consumed = false;
      var key = decode(event);

      var viewer = _this.getViewer(); // If focus was on an input or if the viewer doesn't exist
      // then don't bother doing anything further


      if (!key || !viewer || isInputElement(event.target)) {
        return;
      }

      if (typeof viewer.onKeydown === 'function') {
        consumed = !!viewer.onKeydown(key, event.nativeEvent);
      }

      if (!consumed) {
        switch (key) {
          case 'ArrowLeft':
            _this.navigateLeft();

            consumed = true;
            break;

          case 'ArrowRight':
            _this.navigateRight();

            consumed = true;
            break;

          default: // no-op

        }
      }

      if (consumed) {
        event.preventDefault();
        event.stopPropagation();
      }
    });

    _defineProperty(_assertThisInitialized(_this), "onVersionChange", function (version) {
      var additionalVersionInfo = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      var onVersionChange = _this.props.onVersionChange;
      _this.updateVersionToCurrent = additionalVersionInfo.updateVersionToCurrent;
      onVersionChange(version, additionalVersionInfo);

      _this.setState({
        selectedVersion: version
      });
    });

    _defineProperty(_assertThisInitialized(_this), "handleAnnotationSelect", function (_ref3) {
      var file_version = _ref3.file_version,
          id = _ref3.id,
          target = _ref3.target;
      var _target$location = target.location,
          location = _target$location === void 0 ? {} : _target$location;
      var _this$state2 = _this.state,
          file = _this$state2.file,
          selectedVersion = _this$state2.selectedVersion;
      var annotationFileVersionId = getProp(file_version, 'id');
      var currentFileVersionId = getProp(file, 'file_version.id');
      var currentPreviewFileVersionId = getProp(selectedVersion, 'id', currentFileVersionId);
      var unit = startAtTypes[location.type];

      var viewer = _this.getViewer();

      if (unit && annotationFileVersionId && annotationFileVersionId !== currentPreviewFileVersionId) {
        _this.setState({
          startAt: {
            unit: unit,
            value: location.value
          }
        });
      }

      if (viewer) {
        viewer.emit('scrolltoannotation', {
          id: id,
          target: target
        });
      }
    });

    _defineProperty(_assertThisInitialized(_this), "containerRef", function (container) {
      _this.previewContainer = container;
    });

    var apiHost = props.apiHost,
        cache = props.cache,
        _fileId = props.fileId,
        language = props.language,
        requestInterceptor = props.requestInterceptor,
        responseInterceptor = props.responseInterceptor,
        sharedLink = props.sharedLink,
        sharedLinkPassword = props.sharedLinkPassword,
        _token = props.token;
    _this.id = uniqueid('bcpr_');
    _this.api = new API({
      apiHost: apiHost,
      cache: cache,
      clientName: CLIENT_NAME_CONTENT_PREVIEW,
      language: language,
      requestInterceptor: requestInterceptor,
      responseInterceptor: responseInterceptor,
      sharedLink: sharedLink,
      sharedLinkPassword: sharedLinkPassword,
      token: _token
    });
    _this.state = _objectSpread(_objectSpread({}, _this.initialState), {}, {
      currentFileId: _fileId,
      // eslint-disable-next-line react/no-unused-state
      prevFileIdProp: _fileId
    });
    var _logger = props.logger;

    _logger.onReadyMetric({
      endMarkName: MARK_NAME_JS_READY
    });

    return _this;
  }
  /**
   * Cleanup
   *
   * @return {void}
   */


  _createClass(ContentPreview, [{
    key: "componentWillUnmount",
    value: function componentWillUnmount() {
      // Don't destroy the cache while unmounting
      this.api.destroy(false);
      this.destroyPreview();
    }
    /**
     * Cleans up the preview instance
     */

  }, {
    key: "destroyPreview",
    value: function destroyPreview() {
      var shouldReset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
      var onPreviewDestroy = this.props.onPreviewDestroy;

      if (this.preview) {
        this.preview.destroy();
        this.preview.removeAllListeners();
        this.preview = undefined;
        onPreviewDestroy(shouldReset);
      }
    }
    /**
     * Destroys api instances with caches
     *
     * @private
     * @return {void}
     */

  }, {
    key: "clearCache",
    value: function clearCache() {
      this.api.destroy(true);
    }
    /**
     * Once the component mounts, load Preview assets and fetch file info.
     *
     * @return {void}
     */

  }, {
    key: "componentDidMount",
    value: function componentDidMount() {
      this.loadStylesheet();
      this.loadScript();
      this.fetchFile(this.state.currentFileId);
      this.focusPreview();
    }
  }, {
    key: "componentDidUpdate",
    value:
    /**
     * After component updates, load Preview if appropriate.
     *
     * @return {void}
     */
    function componentDidUpdate(prevProps, prevState) {
      var token = this.props.token;
      var prevToken = prevProps.token;
      var currentFileId = this.state.currentFileId;
      var hasFileIdChanged = prevState.currentFileId !== currentFileId;
      var hasTokenChanged = prevToken !== token;

      if (hasFileIdChanged) {
        this.destroyPreview();
        this.setState({
          isLoading: true,
          selectedVersion: undefined
        });
        this.fetchFile(currentFileId);
      } else if (this.shouldLoadPreview(prevState)) {
        this.destroyPreview(false);
        this.setState({
          isLoading: true
        });
        this.loadPreview();
      } else if (hasTokenChanged) {
        this.updatePreviewToken();
      }
    }
    /**
     * Updates the access token used by preview library
     *
     * @param {boolean} shouldReload - true if preview should be reloaded
     */

  }, {
    key: "updatePreviewToken",
    value: function updatePreviewToken() {
      var shouldReload = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;

      if (this.preview) {
        this.preview.updateToken(this.props.token, shouldReload);
      }
    }
    /**
     * Returns whether or not preview should be loaded.
     *
     * @param {State} prevState - Previous state
     * @return {boolean}
     */

  }, {
    key: "shouldLoadPreview",
    value: function shouldLoadPreview(prevState) {
      var _this$state3 = this.state,
          file = _this$state3.file,
          selectedVersion = _this$state3.selectedVersion;
      var prevFile = prevState.file,
          prevSelectedVersion = prevState.selectedVersion;
      var prevSelectedVersionId = getProp(prevSelectedVersion, 'id');
      var selectedVersionId = getProp(selectedVersion, 'id');
      var prevFileVersionId = getProp(prevFile, 'file_version.id');
      var fileVersionId = getProp(file, 'file_version.id');
      var loadPreview = false;

      if (selectedVersionId !== prevSelectedVersionId) {
        var isPreviousCurrent = fileVersionId === prevSelectedVersionId || !prevSelectedVersionId;
        var isSelectedCurrent = fileVersionId === selectedVersionId || !selectedVersionId; // Load preview if the user has selected a non-current version of the file

        loadPreview = !isPreviousCurrent || !isSelectedCurrent;
      } else if (fileVersionId && prevFileVersionId) {
        // Load preview if the file's current version ID has changed
        loadPreview = fileVersionId !== prevFileVersionId;
      } else {
        // Load preview if file object has newly been populated in state
        loadPreview = !prevFile && !!file;
      }

      return loadPreview;
    }
    /**
     * Returns preview asset urls
     *
     * @return {string} base url
     */

  }, {
    key: "getBasePath",
    value: function getBasePath(asset) {
      var _this$props3 = this.props,
          staticHost = _this$props3.staticHost,
          staticPath = _this$props3.staticPath,
          language = _this$props3.language,
          previewLibraryVersion = _this$props3.previewLibraryVersion;
      var path = "".concat(staticPath, "/").concat(previewLibraryVersion, "/").concat(language, "/").concat(asset);
      var suffix = staticHost.endsWith('/') ? path : "/".concat(path);
      return "".concat(staticHost).concat(suffix);
    }
    /**
     * Determines if preview assets are loaded
     *
     * @return {boolean} true if preview is loaded
     */

  }, {
    key: "isPreviewLibraryLoaded",
    value: function isPreviewLibraryLoaded() {
      return !!global.Box && !!global.Box.Preview;
    }
    /**
     * Loads external css by appending a <link> element
     *
     * @return {void}
     */

  }, {
    key: "loadStylesheet",
    value: function loadStylesheet() {
      var _document = document,
          head = _document.head;
      var url = this.getBasePath('preview.css');

      if (!head || head.querySelector("link[rel=\"stylesheet\"][href=\"".concat(url, "\"]"))) {
        return;
      }

      var link = document.createElement('link');
      link.rel = 'stylesheet';
      link.type = 'text/css';
      link.href = url;
      head.appendChild(link);
    }
    /**
     * Loads external script by appending a <script> element
     *
     * @return {void}
     */

  }, {
    key: "loadScript",
    value: function loadScript() {
      var _document2 = document,
          head = _document2.head;
      var url = this.getBasePath('preview.js');

      if (!head || this.isPreviewLibraryLoaded()) {
        return;
      }

      var previewScript = head.querySelector("script[src=\"".concat(url, "\"]"));

      if (previewScript) {
        return;
      }

      var script = document.createElement('script');
      script.src = url;
      script.addEventListener('load', this.loadPreview);
      head.appendChild(script);
    }
    /**
     * Focuses the preview on load.
     *
     * @return {void}
     */

  }, {
    key: "focusPreview",
    value: function focusPreview() {
      var _this$props4 = this.props,
          autoFocus = _this$props4.autoFocus,
          getInnerRef = _this$props4.getInnerRef;

      if (autoFocus && !isInputElement(document.activeElement)) {
        focus(getInnerRef());
      }
    }
    /**
     * Updates preview cache and prefetches a file
     *
     * @param {BoxItem} file - file to prefetch
     * @return {void}
     */

  }, {
    key: "updatePreviewCacheAndPrefetch",
    value: function updatePreviewCacheAndPrefetch(file, token) {
      if (!this.preview || !file || !file.id) {
        return;
      }

      this.preview.updateFileCache([file]);
      this.preview.prefetch({
        fileId: file.id,
        token: token
      });
    }
    /**
     * Gets the file id
     *
     * @param {string|BoxItem} file - box file or file id
     * @return {string} file id
     */

  }, {
    key: "getFileId",
    value: function getFileId(file) {
      if (typeof file === 'string') {
        return file;
      }

      if (_typeof(file) === 'object' && !!file.id) {
        return file.id;
      }

      throw InvalidIdError;
    }
    /**
     * Prefetches the next few preview files if any
     *
     * @param {Array<string|BoxItem>} files - files to prefetch
     * @return {void}
     */

  }, {
    key: "prefetch",
    value: function () {
      var _prefetch = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(files) {
        var _this2 = this;

        var token, typedIds;
        return regeneratorRuntime.wrap(function _callee2$(_context2) {
          while (1) {
            switch (_context2.prev = _context2.next) {
              case 0:
                token = this.props.token;
                typedIds = files.map(function (file) {
                  return getTypedFileId(_this2.getFileId(file));
                });
                _context2.next = 4;
                return TokenService.cacheTokens(typedIds, token);

              case 4:
                files.forEach(function (file) {
                  var fileId = _this2.getFileId(file);

                  _this2.fetchFile(fileId, noop, noop, {
                    refreshCache: false
                  });
                });

              case 5:
              case "end":
                return _context2.stop();
            }
          }
        }, _callee2, this);
      }));

      function prefetch(_x) {
        return _prefetch.apply(this, arguments);
      }

      return prefetch;
    }()
    /**
     * Calculates the total file fetch time
     *
     * @return {number} the total fetch time
     */

  }, {
    key: "getTotalFileFetchTime",
    value: function getTotalFileFetchTime() {
      if (!this.fetchFileStartTime || !this.fetchFileEndTime) {
        return 0;
      }

      return Math.round(this.fetchFileEndTime - this.fetchFileStartTime);
    }
    /**
     * Handler for 'preview_error' preview event
     *
     * @param {PreviewLibraryError} previewError - the error data emitted from preview
     * @return {void}
     */

  }, {
    key: "addFetchFileTimeToPreviewMetrics",
    value:
    /**
     * Adds in the file fetch time to the preview metrics
     *
     * @param {Object} previewTimeMetrics - the preview time metrics
     * @return {Object} the preview time metrics merged with the files call time
     */
    function addFetchFileTimeToPreviewMetrics(previewTimeMetrics) {
      var totalFetchFileTime = this.getTotalFileFetchTime();
      var rendering = previewTimeMetrics.rendering,
          conversion = previewTimeMetrics.conversion,
          preload = previewTimeMetrics.preload; // We need to add in the total file fetch time to the rendering and total as preview
      // does not do the files call. In the case the file is in the process of
      // being converted, we need to add to conversion instead of the render

      var totalConversion = conversion;
      var totalRendering = rendering;
      var totalPreload = preload;

      if (conversion) {
        totalConversion += totalFetchFileTime;
      } else {
        totalRendering += totalFetchFileTime;
      }

      if (totalPreload) {
        // Preload is optional, depending on file type
        totalPreload += totalFetchFileTime;
      }

      var previewMetrics = {
        conversion: totalConversion,
        rendering: totalRendering,
        total: totalRendering + totalConversion,
        preload: totalPreload
      };
      return previewMetrics;
    }
    /**
     * onLoad function for preview
     *
     * @return {void}
     */

  }, {
    key: "canDownload",
    value:
    /**
     * Returns whether file can be downloaded based on file properties, permissions, and user-defined options.
     *
     * @return {boolean}
     */
    function canDownload() {
      var canDownload = this.props.canDownload;
      var file = this.state.file;
      var isFileDownloadable = getProp(file, 'permissions.can_download', false) && getProp(file, 'is_download_available', false);
      return isFileDownloadable && !!canDownload;
    }
    /**
     * Returns whether file can be annotated based on permissions
     *
     * @return {boolean}
     */

  }, {
    key: "canAnnotate",
    value: function canAnnotate() {
      var showAnnotations = this.props.showAnnotations;
      var file = this.state.file;
      var isFileAnnotatable = getProp(file, 'permissions.can_annotate', false);
      return !!showAnnotations && isFileAnnotatable;
    }
    /**
     * Returns whether a preview should render annotations based on permissions
     *
     * @return {boolean}
     */

  }, {
    key: "canViewAnnotations",
    value: function canViewAnnotations() {
      var showAnnotations = this.props.showAnnotations;
      var file = this.state.file;
      var hasViewAllPermissions = getProp(file, 'permissions.can_view_annotations_all', false);
      var hasViewSelfPermissions = getProp(file, 'permissions.can_view_annotations_self', false);
      return !!showAnnotations && (this.canAnnotate() || hasViewAllPermissions || hasViewSelfPermissions);
    }
  }, {
    key: "handleCanPrint",
    value: function handleCanPrint() {
      var preview = this.getPreview();
      this.setState({
        canPrint: !!preview && (!preview.canPrint || preview.canPrint())
      });
    }
    /**
     * Loads preview in the component using the preview library.
     *
     * @return {void}
     */

  }, {
    key: "fetchFile",
    value:
    /**
     * Fetches a file
     *
     * @param {string} id file id
     * @param {Function|void} [successCallback] - Callback after file is fetched
     * @param {Function|void} [errorCallback] - Callback after error
     * @param {Object|void} [fetchOptions] - Fetch options
     * @return {void}
     */
    function fetchFile(id, successCallback, errorCallback) {
      var fetchOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};

      if (!id) {
        return;
      }

      this.fetchFileStartTime = performance.now();
      this.fetchFileEndTime = null;
      this.api.getFileAPI().getFile(id, successCallback || this.fetchFileSuccessCallback, errorCallback || this.fetchFileErrorCallback, _objectSpread(_objectSpread({}, fetchOptions), {}, {
        fields: PREVIEW_FIELDS_TO_FETCH
      }));
    }
    /**
     * Returns the preview instance
     *
     * @return {Preview} current instance of preview
     */

  }, {
    key: "getFileIndex",
    value:
    /**
     * Finds the index of current file inside the collection
     *
     * @return {number} -1 if not indexed
     */
    function getFileIndex() {
      var currentFileId = this.state.currentFileId;
      var collection = this.props.collection;

      if (!currentFileId || collection.length < 2) {
        return -1;
      }

      return collection.findIndex(function (item) {
        if (typeof item === 'string') {
          return item === currentFileId;
        }

        return item.id === currentFileId;
      });
    }
    /**
     * Shows a preview of a file at the specified index in the current collection.
     *
     * @public
     * @param {number} index - Index of file to preview
     * @return {void}
     */

  }, {
    key: "navigateToIndex",
    value: function navigateToIndex(index) {
      var _this$props5 = this.props,
          collection = _this$props5.collection,
          onNavigate = _this$props5.onNavigate;
      var length = collection.length;

      if (length < 2 || index < 0 || index > length - 1) {
        return;
      }

      var fileOrId = collection[index];
      var fileId = _typeof(fileOrId) === 'object' ? fileOrId.id || '' : fileOrId;
      this.setState({
        currentFileId: fileId
      }, function () {
        // Execute navigation callback
        onNavigate(fileId);
      });
    }
    /**
     * Shows a preview of the previous file.
     *
     * @public
     * @return {void}
     */

  }, {
    key: "refreshSidebar",
    value:
    /**
     * Refreshes the content sidebar panel
     *
     * @return {void}
     */
    function refreshSidebar() {
      var contentSidebar = this.contentSidebar.current;

      if (contentSidebar) {
        contentSidebar.refresh();
      }
    }
    /**
     * Renders the file preview
     *
     * @inheritdoc
     * @return {Element}
     */

  }, {
    key: "render",
    value: function render() {
      var _this$props6 = this.props,
          apiHost = _this$props6.apiHost,
          collection = _this$props6.collection,
          token = _this$props6.token,
          language = _this$props6.language,
          messages = _this$props6.messages,
          className = _this$props6.className,
          contentSidebarProps = _this$props6.contentSidebarProps,
          contentOpenWithProps = _this$props6.contentOpenWithProps,
          hasHeader = _this$props6.hasHeader,
          history = _this$props6.history,
          isLarge = _this$props6.isLarge,
          isVeryLarge = _this$props6.isVeryLarge,
          logoUrl = _this$props6.logoUrl,
          onClose = _this$props6.onClose,
          measureRef = _this$props6.measureRef,
          sharedLink = _this$props6.sharedLink,
          sharedLinkPassword = _this$props6.sharedLinkPassword,
          requestInterceptor = _this$props6.requestInterceptor,
          responseInterceptor = _this$props6.responseInterceptor;
      var _this$state4 = this.state,
          canPrint = _this$state4.canPrint,
          currentFileId = _this$state4.currentFileId,
          error = _this$state4.error,
          file = _this$state4.file,
          isLoading = _this$state4.isLoading,
          isReloadNotificationVisible = _this$state4.isReloadNotificationVisible,
          isThumbnailSidebarOpen = _this$state4.isThumbnailSidebarOpen,
          selectedVersion = _this$state4.selectedVersion;
      var styleClassName = classNames('be bcpr', {
        'bcpr-thumbnails-open': isThumbnailSidebarOpen
      }, className);

      if (!currentFileId) {
        return null;
      }

      var errorCode = getProp(error, 'code');
      var currentExtension = getProp(file, 'id') === currentFileId ? getProp(file, 'extension') : '';
      var currentVersionId = getProp(file, 'file_version.id');
      var selectedVersionId = getProp(selectedVersion, 'id', currentVersionId);
      var onHeaderClose = currentVersionId === selectedVersionId ? onClose : this.updateVersionToCurrent;
      /* eslint-disable jsx-a11y/no-static-element-interactions */

      /* eslint-disable jsx-a11y/no-noninteractive-tabindex */

      return /*#__PURE__*/React.createElement(Internationalize, {
        language: language,
        messages: messages
      }, /*#__PURE__*/React.createElement("div", {
        id: this.id,
        className: styleClassName,
        ref: measureRef,
        onKeyDown: this.onKeyDown,
        tabIndex: 0
      }, hasHeader && /*#__PURE__*/React.createElement(PreviewHeader, {
        file: file,
        logoUrl: logoUrl,
        token: token,
        onClose: onHeaderClose,
        onPrint: this.print,
        canDownload: this.canDownload(),
        canPrint: canPrint,
        onDownload: this.download,
        contentOpenWithProps: contentOpenWithProps,
        canAnnotate: this.canAnnotate(),
        selectedVersion: selectedVersion
      }), /*#__PURE__*/React.createElement("div", {
        className: "bcpr-body"
      }, /*#__PURE__*/React.createElement("div", {
        className: "bcpr-container",
        onMouseMove: this.onMouseMove,
        ref: this.containerRef
      }, file && /*#__PURE__*/React.createElement(Measure, {
        bounds: true,
        onResize: this.onResize
      }, function (_ref4) {
        var previewRef = _ref4.measureRef;
        return /*#__PURE__*/React.createElement("div", {
          ref: previewRef,
          className: "bcpr-content"
        });
      }), /*#__PURE__*/React.createElement(PreviewMask, {
        errorCode: errorCode,
        extension: currentExtension,
        isLoading: isLoading
      }), /*#__PURE__*/React.createElement(PreviewNavigation, {
        collection: collection,
        currentIndex: this.getFileIndex(),
        onNavigateLeft: this.navigateLeft,
        onNavigateRight: this.navigateRight
      })), file && /*#__PURE__*/React.createElement(LoadableSidebar, _extends({}, contentSidebarProps, {
        apiHost: apiHost,
        token: token,
        cache: this.api.getCache(),
        fileId: currentFileId,
        getPreview: this.getPreview,
        getViewer: this.getViewer,
        history: history,
        isDefaultOpen: isLarge || isVeryLarge,
        language: language,
        ref: this.contentSidebar,
        sharedLink: sharedLink,
        sharedLinkPassword: sharedLinkPassword,
        requestInterceptor: requestInterceptor,
        responseInterceptor: responseInterceptor,
        onAnnotationSelect: this.handleAnnotationSelect,
        onVersionChange: this.onVersionChange
      }))), isReloadNotificationVisible && /*#__PURE__*/React.createElement(ReloadNotification, {
        onClose: this.closeReloadNotification,
        onClick: this.loadFileFromStage
      })));
      /* eslint-enable jsx-a11y/no-static-element-interactions */

      /* eslint-enable jsx-a11y/no-noninteractive-tabindex */
    }
  }], [{
    key: "getDerivedStateFromProps",
    value: function getDerivedStateFromProps(props, state) {
      var fileId = props.fileId;

      if (fileId !== state.prevFileIdProp) {
        return {
          currentFileId: fileId,
          prevFileIdProp: fileId
        };
      }

      return null;
    }
  }]);

  return ContentPreview;
}(React.PureComponent);

_defineProperty(ContentPreview, "defaultProps", {
  apiHost: DEFAULT_HOSTNAME_API,
  appHost: DEFAULT_HOSTNAME_APP,
  autoFocus: false,
  canDownload: true,
  className: '',
  collection: [],
  contentOpenWithProps: {},
  contentSidebarProps: {},
  enableThumbnailsSidebar: false,
  hasHeader: false,
  language: DEFAULT_LOCALE,
  onAnnotator: noop,
  onAnnotatorEvent: noop,
  onDownload: noop,
  onError: noop,
  onLoad: noop,
  onNavigate: noop,
  onPreviewDestroy: noop,
  onVersionChange: noop,
  previewLibraryVersion: DEFAULT_PREVIEW_VERSION,
  showAnnotations: false,
  staticHost: DEFAULT_HOSTNAME_STATIC,
  staticPath: DEFAULT_PATH_STATIC_PREVIEW,
  useHotkeys: true
});

export { ContentPreview as ContentPreviewComponent };
export default flow([makeResponsive, withAnnotatorContext, withAnnotations, withRouter, withNavRouter, withFeatureProvider, withLogger(ORIGIN_CONTENT_PREVIEW), withErrorBoundary(ORIGIN_CONTENT_PREVIEW)])(ContentPreview);
//# sourceMappingURL=ContentPreview.js.map