goog.module('gep.provider.LayerProvider');
const {Event,EventTarget} = goog.require('goog.events');
const classlist = goog.require('goog.dom.classlist');
/**
* This provider (singleton) controls the display of all layers
* @extends {EventTarget}
*/
class LayerProvider extends EventTarget
{
constructor()
{
super();
/**
* List of {@Link LayerModel} in use
* If a new layer is added it must be added here with type and name.
* @example
* this.layers_.push(new LayerModel(LayerType.NEWS, 'news'));
* @type {Array<LayerModel>}
* @private
*/
this.layers_ = [];
this.layers_.push(new LayerModel(LayerType.EXHIBIT, 'exhibit'));
this.layers_.push(new LayerModel(LayerType.MEDIA, 'media'));
this.layers_.push(new LayerModel(LayerType.VISITOR, 'visitor'));
this.layers_.push(new LayerModel(LayerType.INSTALLATION, 'installation'));
this.layers_.push(new LayerModel(LayerType.GUIDING, 'guiding'));
this.layers_.push(new LayerModel(LayerType.BLOCKING, 'blocking'));
/**
* List of open/shown layer types
* @type {Map<string,string|null>}
* @private
*/
this.activeLayers_ = new Map();
this.layers_.forEach((layerModel) => {
if(!this.activeLayers_.has(layerModel.type))
this.activeLayers_.set(layerModel.type, null);
});
}
/**
* Displays the layer whose model name corresponds to the specified name.
* Optionally, a data object can be passed to the open layer by events.
* When the layer is reopened {@Link LayerEventType} `SHOW_LAYER` is fired.
* If this layer is already open {@Link LayerEventType} `UPDATE_LAYER`.
* A class is also added to the document element specifying which {@Link LayerType}
* is currently open. (e.g. `has-open-visitor-layer`)
* @param {string} name
* @param {*=} data
*/
show(name, data = null)
{
let layerModel = this.getLayerByName(name);
if(layerModel)
{
if(this.activeLayers_.get(layerModel.type) != name)
{
this.activeLayers_.set(layerModel.type, name);
classlist.add(document.documentElement, 'has-open-'+layerModel.type);
this.dispatchEvent(new LayerEvent(LayerEventType.SHOW_LAYER, layerModel, data));
}
else
{
this.dispatchEvent(new LayerEvent(LayerEventType.UPDATE_LAYER, layerModel, data));
}
}
}
/**
* Hide a specific layer. If no name is specified, all active layers are hidden.
* The {@Link LayerEventType} `HIDE_LAYER` will be fired.
* @param {string|null=} name
*/
hide(name = null)
{
if(name)
{
let layerModel = this.getLayerByName(name);
if(layerModel)
{
if(this.activeLayers_.get(layerModel.type) == name)
{
this.activeLayers_.set(layerModel.type, null);
classlist.remove(document.documentElement, 'has-open-' + layerModel.type);
this.dispatchEvent(new LayerEvent(LayerEventType.HIDE_LAYER, layerModel));
}
}
}
else
{
this.activeLayers_.forEach((name) => {
if(name)
{
let layerModel = this.getLayerByName(name);
if(this.activeLayers_.get(layerModel.type) == name)
{
this.activeLayers_.set(layerModel.type, null);
classlist.remove(document.documentElement, 'has-open-'+layerModel.type);
this.dispatchEvent(new LayerEvent(LayerEventType.HIDE_LAYER, layerModel));
}
}
});
}
}
/**
* Finds and returns a LayerModel with a given name.
* @param {string} name
* @return {LayerModel}
*/
getLayerByName(name)
{
for(let i=0; i<this.layers_.length; i++)
{
if (this.layers_[i].name == name)
return this.layers_[i];
}
return null;
}
/**
* Checked if a specific layer with the name is open.
* If no name is specified, it is checked whether any layer is open in general.
* @param {string|null=} name
* @return {boolean}
*/
isOpen(name = null)
{
if(name)
{
let layerModel = this.getLayerByName(name);
return layerModel != null && this.activeLayers_.get(layerModel.type) != null;
}
else
{
let isOpen = false;
this.activeLayers_.forEach((name) => {
if(name)
{
let layerModel = this.getLayerByName(name);
if(layerModel && this.activeLayers_.get(layerModel.type) != null)
isOpen = true;
}
});
return isOpen
}
}
/**
* Getter
* @return {Map<string,string|null>}
*/
get activeLayers()
{
return this.activeLayers_;
}
}
goog.addSingletonGetter(LayerProvider);
/**
* @enum {string}
*/
const LayerType = {
/** exhibit-layer */ EXHIBIT: 'exhibit-layer',
/** guiding-layer */ GUIDING: 'guiding-layer',
/** installation-frame */ INSTALLATION: 'installation-frame',
/** media-layer */ MEDIA: 'media-layer',
/** visitor-layer */ VISITOR: 'visitor-layer',
/** blocking-layer */ BLOCKING: 'blocking-layer'
};
/**
* Model for a layer consists of its type {@Link LayerType} and
* a unique name that can be used later for an exact assignment.
*/
class LayerModel
{
/**
* @param {string} type Use {@Link LayerType}
* @param {string} name Unique name for an exact assignment
*/
constructor(type, name)
{
/**
* Use {@Link LayerType}
* @type {string}
*/
this.type = type;
/**
* Unique name for an exact assignment
* @type {string}
*/
this.name = name;
}
}
/**
* Own event that is used to open, update and close the layer by the {@Link LayerProvider}
* and can also be caught by it. The {@Link LayerModel} is always sent along for an exact assignment.
* In addition, the optional data parameter can be used to pass further values to the layer via the event.
* @extends {Event}
*/
class LayerEvent extends Event
{
/**
* @param {string} type
* @param {LayerModel} layer
* @param {*=} data Optional data which should be passed to the layer by this event
*/
constructor(type, layer, data = null)
{
super(type);
/**
* @type {LayerModel}
*/
this.layer = layer;
/**
* Optional data which should be passed to the layer by this event.
* @type {*}
*/
this.data = data;
}
};
/**
* @enum {string}
*/
const LayerEventType = {
/** show-layer */ SHOW_LAYER: 'show-layer',
/** hide-layer */ HIDE_LAYER: 'hide-layer',
/** update-layer */ UPDATE_LAYER: 'update-layer',
};
exports = {LayerProvider,LayerType,LayerModel,LayerEvent,LayerEventType};