Liferay.Loader.define("frontend-js-spa-web@4.0.41/liferay/app/App.es", ['module', 'exports', 'require', 'frontend-js-web', 'frontend-js-metal-web$metal', 'frontend-js-metal-web$metal-dom', 'frontend-js-spa-web$senna', '../surface/Surface.es', '../util/Utils.es'], function (module, exports, require) {
  var define = undefined;
  var global = window;
  {
    Object.defineProperty(exports, "__esModule", {
      value: true
    });
    exports.default = void 0;

    var _frontendJsWeb = require("frontend-js-web");

    var _metal = _interopRequireDefault(require("frontend-js-metal-web$metal"));

    var _metalDom = _interopRequireDefault(require("frontend-js-metal-web$metal-dom"));

    var _senna = require("frontend-js-spa-web$senna");

    var _Surface = _interopRequireDefault(require("../surface/Surface.es"));

    var _Utils = _interopRequireDefault(require("../util/Utils.es"));

    function _interopRequireDefault(obj) {
      return obj && obj.__esModule ? obj : { default: obj };
    }

    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 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 _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;
    }

    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 _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 _get(target, property, receiver) {
      if (typeof Reflect !== "undefined" && Reflect.get) {
        _get = Reflect.get;
      } else {
        _get = function _get(target, property, receiver) {
          var base = _superPropBase(target, property);if (!base) return;var desc = Object.getOwnPropertyDescriptor(base, property);if (desc.get) {
            return desc.get.call(receiver);
          }return desc.value;
        };
      }return _get(target, property, receiver || target);
    }

    function _superPropBase(object, property) {
      while (!Object.prototype.hasOwnProperty.call(object, property)) {
        object = _getPrototypeOf(object);if (object === null) break;
      }return object;
    }

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

    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);
    }

    var PROPAGATED_PARAMS = ['bodyCssClass'];
    /**
     * LiferayApp
     *
     * Inherits from `senna/src/app/App` and adds the following Liferay specific
     * behavior to Senna's default App:
     * <ul>
     *   <li> Makes cache expiration time configurable from System Settings</li>
     *   <li>Lets you set valid status codes (Liferay's default valid status codes
     *   are listed in {@link https://docs.liferay.com/portal/7.1/javadocs/portal-kernel/com/liferay/portal/kernel/servlet/ServletResponseConstants.html|ServletResponseConstants.java})
     *   <li>Shows alert notifications when requests take too long or when they fail</li>
     *   <li>Adds a portletBlacklist option that lets you exclude specific portlets
     *   from the SPA lifecycle.</li>
     * </ul>
     */

    var LiferayApp = /*#__PURE__*/function (_App) {
      _inherits(LiferayApp, _App);

      /**
       * @inheritDoc
       */
      function LiferayApp() {
        var _this;

        _classCallCheck(this, LiferayApp);

        _this = _possibleConstructorReturn(this, _getPrototypeOf(LiferayApp).call(this));
        _this.lastLocale = themeDisplay.getLanguageId();
        _this.portletsBlacklist = {};
        _this.validStatusCodes = [];

        _this.setShouldUseFacade(true);

        _this.timeout = Math.max(Liferay.SPA.requestTimeout, 0) || _Utils.default.getMaxTimeout();
        _this.timeoutAlert = null;
        var exceptionsSelector = Liferay.SPA.navigationExceptionSelectors;

        _this.setFormSelector('form' + exceptionsSelector);

        _this.setLinkSelector('a' + exceptionsSelector);

        _this.setLoadingCssClass('lfr-spa-loading');

        _this.on('beforeNavigate', _this.onBeforeNavigate);

        _this.on('endNavigate', _this.onEndNavigate);

        _this.on('endNavigate', _this._checkLanguageChange);

        _this.on('navigationError', _this.onNavigationError);

        _this.on('startNavigate', _this.onStartNavigate);

        Liferay.on('beforeScreenFlip', _Utils.default.resetAllPortlets);
        Liferay.on('beforeScreenFlip', Liferay.destroyUnfulfilledPromises);
        Liferay.on('io:complete', _this.onLiferayIOComplete, _assertThisInitialized(_this));
        var body = document.body;

        if (!body.id) {
          body.id = 'senna_surface' + _metal.default.getUid();
        }

        _this.addSurfaces(new _Surface.default(body.id));

        _metalDom.default.append(body, '<div class="lfr-spa-loading-bar"></div>');

        return _this;
      }
      /**
       * Retrieves or create a screen instance to a path. This method overrides
       * the default one to avoid ActionURLScreens to be cached and reused across
       * navigations causing different lifecycle mechanisms to be called on live
       * documents instead of on inert fragments
       * @param {!string} path Path containing the querystring part.
       * @return {Screen}
       */

      _createClass(LiferayApp, [{
        key: "createScreenInstance",
        value: function createScreenInstance(path, route) {
          if (path === this.activePath) {
            var uri = new URL(path, window.location.origin);

            if (uri.searchParams.get('p_p_lifecycle') === '1') {
              this.activePath = this.activePath + "__".concat(_metal.default.getUid());
              this.screens[this.activePath] = this.screens[path];
              delete this.screens[path];
            }
          }

          return _get(_getPrototypeOf(LiferayApp.prototype), "createScreenInstance", this).call(this, path, route);
        }
        /**
         * Returns the cache expiration time configuration. This value comes from
         * System Settings. The configuration is set upon App initialization
         * @See {@link https://github.com/liferay/liferay-portal/blob/7.1.x/modules/apps/frontend-js/frontend-js-spa-web/src/main/resources/META-INF/resources/init.tmpl|init.tmpl}
         * @return {!Number} The `cacheExpirationTime` value
         */

      }, {
        key: "getCacheExpirationTime",
        value: function getCacheExpirationTime() {
          return Liferay.SPA.cacheExpirationTime;
        }
        /**
         * Returns the valid status codes accepted by Liferay. These values
         * come from {@link https://docs.liferay.com/portal/7.1/javadocs/portal-kernel/com/liferay/portal/kernel/servlet/ServletResponseConstants.html|ServletResponseConstants.java}.
         * @return {!Array} The `validStatusCodes` property
         */

      }, {
        key: "getValidStatusCodes",
        value: function getValidStatusCodes() {
          return this.validStatusCodes;
        }
        /**
         * Returns whether the cache is enabled. Cache is considered enabled
         * when {@link LiferayApp#getCacheExpirationTime|getCacheExpirationTime} is
         * greater than zero.
         * @return {!Boolean} True if cache is enabled
         */

      }, {
        key: "isCacheEnabled",
        value: function isCacheEnabled() {
          return this.getCacheExpirationTime() > -1;
        }
        /**
         * Returns whether a given portlet element is in a blacklisted portlet
         * that should not behave like a SPA
         * @param  {!String} element The portlet boundary DOM node
         * @return {!Boolean} True if portlet element is blacklisted
         */

      }, {
        key: "isInPortletBlacklist",
        value: function isInPortletBlacklist(element) {
          return Object.keys(this.portletsBlacklist).some(function (portletId) {
            var boundaryId = _Utils.default.getPortletBoundaryId(portletId);

            var portlets = document.querySelectorAll('[id^="' + boundaryId + '"]');
            return Array.prototype.slice.call(portlets).some(function (portlet) {
              return _metalDom.default.contains(portlet, element);
            });
          });
        }
        /**
         * Returns whether a given Screen's cache is expired. The expiration timeframe
         * is based on the value returned by {@link LiferayApp#getCacheExpirationTime|getCacheExpirationTime}.
         * @param  {!Screen} screen The Senna Screen
         * @return {!Boolean} True if the cache has expired
         */

      }, {
        key: "isScreenCacheExpired",
        value: function isScreenCacheExpired(screen) {
          var screenCacheExpired = false;

          if (this.getCacheExpirationTime() !== 0) {
            var lastModifiedInterval = new Date().getTime() - screen.getCacheLastModified();
            screenCacheExpired = lastModifiedInterval > this.getCacheExpirationTime();
          }

          return screenCacheExpired;
        }
        /**
         * A callback for Senna's `beforeNavigate` event. The cache is cleared
         * for all screens when the flag `Liferay.SPA.clearScreensCache`
         * is set or when a form submission is about to occur. This method also
         * exposes the `beforeNavigate` event to the Liferay global object so
         * anyone can listen to it.
         * @param  {!Object} data Data about the event
         * @param  {!Event} event The event object
         */

      }, {
        key: "onBeforeNavigate",
        value: function onBeforeNavigate(data, event) {
          if (Liferay.SPA.clearScreensCache || data.form) {
            this.clearScreensCache();
          }

          this._clearLayoutData();

          data.path = this._propagateParams(data);
          Liferay.fire('beforeNavigate', {
            app: this,
            originalEvent: event,
            path: data.path
          });
        }
        /**
         * A private event handler function, called when the
         * `dataLayoutConfigReady` event is fired on the Liferay object,
         * that initializes `Liferay.Layout`
         * @param  {!Event} event The event object
         */

      }, {
        key: "onDataLayoutConfigReady_",
        value: function onDataLayoutConfigReady_() {
          if (Liferay.Layout) {
            Liferay.Layout.init(Liferay.Data.layoutConfig);
          }
        }
        /**
         * @inheritDoc
         * Overrides Senna's default `onDocClickDelegate_ handler`. Halts
         * SPA behavior if the click target is inside a blacklisted portlet.
         * Reduces navigations from multiple clicks to a single navigation.
         *
         * @param  {!Event} event The event object
         */

      }, {
        key: "onDocClickDelegate_",
        value: function onDocClickDelegate_(event) {
          if (this.isInPortletBlacklist(event.delegateTarget) || event.detail > 1) {
            return;
          }

          _get(_getPrototypeOf(LiferayApp.prototype), "onDocClickDelegate_", this).call(this, event);
        }
        /**
         * @inheritDoc
         * Overrides Senna's default `onDocSubmitDelegate_ handler` and
         * halts SPA behavior if the form is inside a blacklisted
         * portlet
         * @param  {!Event} event The event object
         */

      }, {
        key: "onDocSubmitDelegate_",
        value: function onDocSubmitDelegate_(event) {
          if (this.isInPortletBlacklist(event.delegateTarget)) {
            return;
          }

          _get(_getPrototypeOf(LiferayApp.prototype), "onDocSubmitDelegate_", this).call(this, event);
        }
        /**
         * Callback for Senna's `endNavigate` event that exposes it
         * to the Liferay global object
         * @param  {!Event} event The event object
         */

      }, {
        key: "onEndNavigate",
        value: function onEndNavigate(event) {
          Liferay.fire('endNavigate', {
            app: this,
            error: event.error,
            path: event.path
          });

          if (!this.pendingNavigate) {
            this._clearRequestTimer();

            this._hideTimeoutAlert();
          }

          if (!event.error) {
            this.dataLayoutConfigReadyHandle_ = Liferay.once('dataLayoutConfigReady', this.onDataLayoutConfigReady_);
          }

          this._adjustScrollTop();

          AUI().Get._insertCache = {};
          Liferay.DOMTaskRunner.reset();
        }
        /**
         * Callback for Liferay's `io:complete` event that clears screens cache when
         * an async request occurs
         */

      }, {
        key: "onLiferayIOComplete",
        value: function onLiferayIOComplete() {
          this.clearScreensCache();
        }
        /**
         * Callback for Senna's `navigationError` event that displays
         * an alert message to the user with information about the error
         * @param  {!Event} event The event object
         */

      }, {
        key: "onNavigationError",
        value: function onNavigationError(event) {
          if (event.error.requestPrematureTermination) {
            window.location.href = event.path;
          } else if (event.error.invalidStatus || event.error.requestError || event.error.timeout) {
            var message = Liferay.Language.get('there-was-an-unexpected-error.-please-refresh-the-current-page');

            if (Liferay.SPA.debugEnabled) {
              console.error(event.error);

              if (event.error.invalidStatus) {
                message = Liferay.Language.get('the-spa-navigation-request-received-an-invalid-http-status-code');
              }

              if (event.error.requestError) {
                message = Liferay.Language.get('there-was-an-unexpected-error-in-the-spa-request');
              }

              if (event.error.timeout) {
                message = Liferay.Language.get('the-spa-request-timed-out');
              }
            }

            Liferay.Data.layoutConfig = this.dataLayoutConfig_;

            this._createNotification({
              message: message,
              title: Liferay.Language.get('error'),
              type: 'danger'
            });
          }
        }
        /**
         * Callback for Senna's `startNavigate` event that exposes it
         * to the Liferay global object
         * @param  {!Event} event The event object
         */

      }, {
        key: "onStartNavigate",
        value: function onStartNavigate(event) {
          Liferay.fire('startNavigate', {
            app: this,
            path: event.path
          });

          this._startRequestTimer(event.path);
        }
        /**
         * Sets the `portletsBlacklist` property
         * @param  {!Object} portletsBlacklist
         */

      }, {
        key: "setPortletsBlacklist",
        value: function setPortletsBlacklist(portletsBlacklist) {
          this.portletsBlacklist = portletsBlacklist;
        }
        /**
         * Sets the `validStatusCodes` property
         * @param  {!Array} validStatusCodes
         */

      }, {
        key: "setValidStatusCodes",
        value: function setValidStatusCodes(validStatusCodes) {
          this.validStatusCodes = validStatusCodes;
        }
        /**
         * Adjust scroll position to account for Control Menu.
         */

      }, {
        key: "_adjustScrollTop",
        value: function _adjustScrollTop() {
          var controlMenuContainer = document.querySelector('.control-menu-container');

          if (controlMenuContainer) {
            var controlMenuContainerScroll = controlMenuContainer.offsetHeight || 0;
            window.scrollBy(0, -controlMenuContainerScroll);
          }
        }
        /**
         * In case there is a language change during navigation we need to
         * fully reload to avoid modules being loaded twice in the browser
         */

      }, {
        key: "_checkLanguageChange",
        value: function _checkLanguageChange() {
          var currentLocale = themeDisplay.getLanguageId();

          if (!this.lastLocale) {
            this.lastLocale = currentLocale;
          } else if (this.lastLocale !== currentLocale) {
            window.location.reload();
          }
        }
        /**
         * Clears and detaches event handlers for Liferay's `dataLayoutConfigReady`
         * event
         */

      }, {
        key: "_clearLayoutData",
        value: function _clearLayoutData() {
          this.dataLayoutConfig_ = Liferay.Data.layoutConfig;
          Liferay.Data.layoutConfig = null;

          if (this.dataLayoutConfigReadyHandle_) {
            this.dataLayoutConfigReadyHandle_.detach();
            this.dataLayoutConfigReadyHandle_ = null;
          }
        }
        /**
         * Clears the timer that notifies the user when the SPA request
         * takes longer than the thresshold time configured in the
         * `Liferay.SPA.userNotification.timeout` System Settings property
         */

      }, {
        key: "_clearRequestTimer",
        value: function _clearRequestTimer() {
          if (this.requestTimer) {
            clearTimeout(this.requestTimer);
          }
        }
        /**
         * Creates a user notification
         * @param  {!Object} configuration object that's passed to `Liferay.Notification`
         * @return {!Promise} A promise that renders a notification when
         * resolved
         */

      }, {
        key: "_createNotification",
        value: function _createNotification(config) {
          return new Promise(function (resolve) {
            resolve((0, _frontendJsWeb.openToast)(_objectSpread({
              type: 'warning'
            }, config)));
          });
        }
        /**
         * Hides the request timeout alert
         */

      }, {
        key: "_hideTimeoutAlert",
        value: function _hideTimeoutAlert() {
          if (this.timeoutAlert) {
            this.timeoutAlert.dispose();
          }
        }
      }, {
        key: "_propagateParams",
        value: function _propagateParams(data) {
          var activeUri = this.activePath ? new URL(this.activePath, window.location.origin) : new URL(window.location.href);
          var activePpid = activeUri.searchParams.get('p_p_id');
          var nextUri = new URL(data.path, window.location.origin);
          var nextPpid = nextUri.searchParams.get('p_p_id');

          if (nextPpid && nextPpid === activePpid) {
            PROPAGATED_PARAMS.forEach(function (paramKey) {
              var paramName = "_".concat(nextPpid, "_").concat(paramKey);
              var paramValue = activeUri.searchParams.get(paramName);

              if (paramValue) {
                nextUri.searchParams.set(paramName, paramValue);
              }
            });
          }

          return nextUri.toString();
        }
        /**
         * Starts the timer that shows the user a notification when the SPA
         * request takes longer than the threshold time configured in the
         * `Liferay.SPA.userNotification.timeout` System Settings property
         * @param  {!String} path The path that may time out
         */

      }, {
        key: "_startRequestTimer",
        value: function _startRequestTimer(path) {
          var _this2 = this;

          this._clearRequestTimer();

          if (Liferay.SPA.userNotification.timeout > 0) {
            this.requestTimer = setTimeout(function () {
              Liferay.fire('spaRequestTimeout', {
                path: path
              });

              _this2._hideTimeoutAlert();

              _this2._createNotification({
                message: Liferay.SPA.userNotification.message,
                title: Liferay.SPA.userNotification.title,
                type: 'warning'
              }).then(function (alert) {
                _this2.timeoutAlert = alert;
              });
            }, Liferay.SPA.userNotification.timeout);
          }
        }
        /**
         * @inheritDoc
         */

      }, {
        key: "updateHistory_",
        value: function updateHistory_(title, path, state, opt_replaceHistory) {
          if (state && state.redirectPath) {
            state.path = state.redirectPath;
          }

          _get(_getPrototypeOf(LiferayApp.prototype), "updateHistory_", this).call(this, title, path, state, opt_replaceHistory);
        }
      }]);

      return LiferayApp;
    }(_senna.App);

    var _default = LiferayApp;
    exports.default = _default;
    //# sourceMappingURL=App.es.js.map
  }
});
//# sourceMappingURL=App.es.js.map