"use strict";
/**
* @typedef Options
* @property {ScreenTransition} [transition]
* @property {ScrollValues} [viewportScroll]
* @property {boolean} [isOverlay]
*/
/**
* Item on the history stack
*/
export class NavigationItem {
/**
* **Not for external use**. Should only be called by {@link Manager}
* @param {Manager} parent
* @param {string} id
* @param {object} state
* @param {Options} [options]
* @hideconstructor
*/
constructor(parent, id, state, options) {
options = {
transition: parent.transition,
viewportScroll: {x:0, y:0},
isOverlay: false,
...options
};
/**
* @type {string}
* @readonly
*/
this.id = id;
/**
* @type {Manager}
* @readonly
*/
this.parent = parent;
this._stateValue = state;
this._hydrated = null;
this._element = null;
/**
* @type {number}
* @package
*/
this.viewportId = -1;
/**
* @type {ScrollValues}
* @package
*/
this.viewportScroll = options.viewportScroll;
/**
* @type {ScreenTransition}
* @readonly
*/
this.transition = options.transition;
/**
* @type {boolean}
* @readonly
*/
this.isOverlay = options.isOverlay;
this._tempViewportId = '';
}
/**
* @type {boolean}
* @package
*/
get isHydrated() {
return null != this._hydrated;
}
/**
* Return the state of this screen. Could be from the stored state if the screen is not active.
* Or the result of the {@link Screen#getState} callback
* @return {object}
* @public
*/
getState() {
if( ! this.isHydrated || ! this._hydrated.getState)
return this._stateValue;
const s = this._hydrated.getState() || {};
return s;
}
/**
* @type {Number}
* @package
*/
get tempViewportId() {return this._tempViewportId}
set tempViewportId (value) {
this._tempViewportId = value;
if(this._element)
this._element.setAttribute('slot', this.slot)
}
/**
* @type {string}
* @package
*/
get slot() {
return this.tempViewportId || this.viewportId || 'none';
}
/**
* Stores the current state and viewport scroll info.
* Needed to save the screen before it is disconnected.
* @package
*/
preserveState() {
this._stateValue = this.getState();
this.viewportScroll = this.getScroll();
}
/**
* @return {ScrollValues}
* @package
*/
getScroll() {
if( ! this._element)
throw new Error ('Setting scroll without element')
return {x:this._element.scrollLeft, y:this._element.scrollTop}
}
/**
* @param {ScrollValues} value
* @package
*/
setScroll(value) {
if( ! this._element)
throw new Error ('Setting scroll without element')
this._element.scrollLeft = value && value.x ? value.x : 0;
this._element.scrollTop = value && value.y ? value.y : 0;
}
/**
* Get the currently hydrated element representing this screen, or hydrate
* a new element
* @return {HTMLElement}
* @package
*/
hydrate() {
if (this._hydrated || ! this.parent.screenFactory)
return this._element;
this._element = document.createElement('div');
this._element.setAttribute('slot', this.slot);
this._element.style.overflow = 'auto';
this._element.style.height = this._element.style.width = '100%';
if(this.isOverlay) {
this._element.style.position = 'fixed';
this._element.style.top = this._element.style.left = '0';
}
this.parent.appendChild(this._element);
const r = this.parent.screenFactory(this.id, this._stateValue, this._element);
if( ! r)
throw new Error('screen factory did not return a value');
if( 'function' != typeof r.getState)
throw new Error('screen factory did not return an object with a getState function');
this.setScroll(this.viewportScroll);
this._hydrated = r;
this._stateValue = null;
}
/**
* Removes this screen from the DOM and calls the disconnect method
* @package
*/
dehydrate() {
if(null == this._hydrated)
return;
if('function' == typeof this._hydrated.disconnect)
this._hydrated.disconnect(this._element)
this._element.parentElement.removeChild(this._element);
this._hydrated = null;
this._element = null;
}
}
export default NavigationItem;