goog.module('gep.components.HintBox');
const Completer = goog.require('clulib.async.Completer');
const {Component} = goog.require('clulib.cm');
const {listen,unlisten,EventType} = goog.require('goog.events');
const dataset = goog.require('goog.dom.dataset');
const classlist = goog.require('goog.dom.classlist');
/**
* This component takes care of the display of hint boxes in the application
* Component is used from {@Link https://www.npmjs.com/package/clulib}
* @extends {Component}
*/
class HintBox extends Component
{
constructor()
{
super();
/**
* Timeout id for the automatic disappearance
* @type {number}
* @private
*/
this.visibleTimeout_ = 0;
/**
* Defines if the hint box is currently displayed
* @type {boolean}
* @private
*/
this.isVisible_ = false;
/**
* Active hint box type. Use {@Link HintBoxContentType}.
* @type {string}
* @private
*/
this.currentContentType_ = '';
/**
* Completer is a helper which returns a promise. Its solved if open hint box is closed.
* @type {Completer}
* @private
*/
this.completer_ = null;
/**
* List of all certain hint box content types which has already been displayed.
* @type {Array<string>}
* @private
*/
this.shownContentTypy_ = [];
/**
* Dom element for the close button
* @type {NodeList}
* @private
*/
this.closeButtons_ = null;
}
/**
* Component is ready and had loaded all dependencies (inherit method waitFor and sub components).
* @inheritDoc
*/
onInit()
{
super.onInit();
/**
* List of hint box contents defined by the class `.hint-box-content` and the attribute `data-content=type`
* @type {NodeList}
* @private
*/
this.contents_ = this.getElement().querySelectorAll('.hint-box-content[data-content]');
}
/**
* Displays the hint box of a given type and activates all interactive elements of the hint box content
* The method returns a Promise that is resolved when the hint box is closed.
* The type is assigned by setting the attribute to the hint box content element in the dom `app\viwes.index.php`.
* @example <caption>{@Link HintBoxContentType} `NAVIGATION_MOVEMENT`</caption>
* <div class="hint-box-content" data-content="navigation-movement"> ...
* @param {string} contentType Use {@Link HintBoxContentType}
* @param {number} duration
* @return {Promise}
*/
show(contentType, duration = 4)
{
if(this.completer_ && !this.completer_.hasCompleted())
this.completer_.reject('Hint box animation was interrupted!');
this.completer_ = new Completer();
if(this.shownContentTypy_.indexOf(contentType) == -1)
this.shownContentTypy_.push(contentType);
let activeContent = null;
this.contents_.forEach((content) => {
let type = dataset.get(/** @type {Element} */ (content), 'content');
if(contentType == type)
activeContent = content;
classlist.enable(/** @type {Element} */ (content), 'is-visible', contentType == type);
});
dataset.set(this.getElement(), 'type', contentType);
this.closeButtons_ = activeContent.querySelectorAll('.hint-box-close');
this.closeButtons_.forEach((button) => {
listen(button, EventType.CLICK, this.handleCloseClick_, false, this);
});
this.isVisible_ = true;
this.currentContentType_ = contentType;
classlist.remove(this.getElement(), 'is-visible');
setTimeout(() => {classlist.add(this.getElement(), 'is-visible');}, 0);
clearTimeout(this.visibleTimeout_);
if(duration > 0)
{
this.visibleTimeout_ = setTimeout(() => {
this.hide();
}, duration * 1000);
}
return this.completer_.getPromise();
}
/**
* Handle hint box close click
* @private
*/
handleCloseClick_()
{
if(this.currentContentType_ == HintBoxContentType.ACTIVATE_AUDIO)
classlist.add(document.documentElement, 'activated-audio');
this.hide();
}
/**
* Hides the hint box and deactivates all interactive elements of the hint box content
* @param {string=} contentType Optional {@Link HintBoxContentType} if the methode should only hide a specific type of hint box.
*/
hide(contentType = '')
{
if(contentType != '' && contentType != this.currentContentType_)
return;
clearTimeout(this.visibleTimeout_);
this.visibleTimeout_ = setTimeout(() => {
if(this.completer_ && !this.completer_.hasCompleted())
this.completer_.resolve();
}, 500);
if(this.closeButtons_) {
this.closeButtons_.forEach((button) => {
unlisten(button, EventType.CLICK, this.handleCloseClick_, false, this);
});
}
this.closeButtons_ = null;
this.isVisible_ = false;
this.currentContentType_ = '';
classlist.remove(this.getElement(), 'is-visible');
}
/**
* Checked if a certain hint box content type has already been displayed.
* @param {string} contentType Use {@Link HintBoxContentType}
* @return {boolean}
*/
contentWasShown(contentType)
{
return this.shownContentTypy_.indexOf(contentType) != -1;
}
/**
* Getter
* @return {boolean}
*/
get isVisible()
{
return this.isVisible_;
}
}
/**
* @enum {string}
*/
const HintBoxContentType = {
/** navigation-movement */ NAVIGATION_MOVEMENT: 'navigation-movement',
/** navigation-perspective */ NAVIGATION_PERSPECTIVE: 'navigation-perspective',
/** navigation-topview */ NAVIGATION_TOPVIEW: 'navigation-topview',
/** artwork-info */ ARTWORK_INFO: 'artwork-info',
/** artwork-single-view */ ARTWORK_SINGLE_VIEW: 'artwork-single-view',
/** artwork-loading-highres */ ARTWORK_LOADING_HIGHRES: 'artwork-loading-highres',
/** activate-audio */ ACTIVATE_AUDIO: 'activate-audio',
/** activate-reshuffling */ ACTIVATE_RESHUFFLING: 'activate-reshuffling'
};
exports = {HintBox,HintBoxContentType};