define([
'module',
'core/js/api/router/AbstractRouter',
'core/js/api/router/RouterState',
'core/js/spi/router/RouterStateObserver',
'viewmodel/js/api/DataSemanticsType',
'viewmodel/js/api/context/BookmarkData',
'viewmodel/js/api/context/ContextualData'
], function(
module,
AbstractRouter,
RouterState,
RouterStateObserver,
DataSemanticsType,
BookmarkData,
ContextualData
) {
'use strict';
/**
* RouterStateObserver implementation which handles the browser's
* History API to behave propertly in combination with internal
* navigation actions.
*
* @returns {HistoryApiRouterStateObserver}
* @constructor
* @private
*/
var HistoryApiRouterStateObserver = function() {
AbcsLib.checkThis(this);
RouterStateObserver.apply(this, arguments);
this._latestPageState;
};
AbcsLib.extend(HistoryApiRouterStateObserver, RouterStateObserver);
HistoryApiRouterStateObserver._LOGGER = Logger.get(module.id);
HistoryApiRouterStateObserver.prototype.ID = 'HistoryApiRouterStateObserver';
HistoryApiRouterStateObserver.prototype.pushState = function(state) {
// treat the superflous index.html
if (document.location.pathname === '/index.html') {
history.replaceState(null, null, '/');
return;
}
this._latestPageState = state;
var targetUrl = AbstractRouter.__treatPath(state.url);
history.pushState(state, null, targetUrl);
HistoryApiRouterStateObserver._LOGGER.debug('URL requested \'' + state.url + '\', resolved to \'' + targetUrl + '\'');
};
HistoryApiRouterStateObserver.prototype.updateState = function(state) {
state = history.state ? RouterState.create(history.state).enhance(state) : state;
try {
history.replaceState(state, null, AbstractRouter.__treatPath(state.url));
} catch (error) {
this._updateContextualDataWithBookmark(state);
history.replaceState(state, null, AbstractRouter.__treatPath(state.url));
HistoryApiRouterStateObserver._LOGGER.warn('Error by saving full contextual data during page leave, switching to bookmark instead, pageID: ' + state.pageId + ', error:\n' + error);
}
};
HistoryApiRouterStateObserver.prototype.beforeRestoreState = function(state, pageViewModel) {
// The History API is not capable to change the previous state before switching to the new
// one. Instead of that we are saving that last state into the temporary variable.
// Also this recovers the state if the last state's URL equals to the new url and completed flag is set.
if (state && this._latestPageState) {
// store the last state - BCK/FWD navigation will not invoke page deactivation event
if (state.url !== this._latestPageState.url && !this._latestPageState.complete) {
this._completeLatestPageState(pageViewModel);
} else if (state.url === this._latestPageState.url && !state.complete) {
RouterState.enhanceSerialized(state, this._latestPageState);
this.updateState(state);
this._latestPageState = undefined;
}
}
};
HistoryApiRouterStateObserver.prototype._completeLatestPageState = function(pageViewModel) {
if (!pageViewModel || !this._latestPageState) {
return;
}
this._latestPageState.enhance({
contextualData: pageViewModel.getContextualData() ? pageViewModel.getContextualData().toJSON() : undefined,
bookmarkData: pageViewModel.getBookmark() ? pageViewModel.getBookmark().toJSON() : undefined,
complete: true
});
};
/**
* Replaces the former contextual data with the bookmark data.
* <p>
* Removes the extra bookmark data from the state then.
*
* @param {Object} state serialized router state
*/
HistoryApiRouterStateObserver.prototype._updateContextualDataWithBookmark = function(state) {
if (state.contextualData) {
var formerContextualData = ContextualData.fromJSON(state.contextualData);
var bookmarkData = BookmarkData.fromJSON(state.bookmarkData);
var bookmarkContextualData = new ContextualData(
bookmarkData,
DataSemanticsType.BOOKMARK,
formerContextualData.getNavigationContext());
state.contextualData = bookmarkContextualData.toJSON();
delete state.bookmarkData;
}
};
return AbcsLib.initSingleton(HistoryApiRouterStateObserver);
});