(function() {
/** @typedef {'full'|'client'|'explicit'|'explicitFull'} Help4.control2.Lightbox.Sizing */
/**
* @typedef {Help4.control2.Control.Params} Help4.control2.Lightbox.Params
* @property {?Help4.control2.Lightbox.Sizing} [sizing = 'full']
* @property {?Help4.control2.SizeWH} [size = null]
* @property {?string} [url = null]
* @property {?string} [content = null]
* @property {Help4.control2.AreaXYWH} [clientArea = {x: 0, y: 0, w: 0, h: 0}]
* @property {boolean} [fullCover = false]
* @property {boolean} [showDetach = false]
* @property {string} [checkboxText = '']
*/
/**
* Lightbox control
* @augments Help4.control2.Control
* @property {Help4.control2.Lightbox.Sizing} sizing
* @property {?Help4.control2.SizeWH} size
* @property {?string} url
* @property {?string} content
* @property {Help4.control2.AreaXYWH} clientArea
* @property {boolean} fullCover
* @property {boolean} showDetach
* @property {string} checkboxText
* @property {?Help4.control2.button.Option} _notAgain
* @property {?Help4.control2.button.Button} _detach
* @property {?Help4.control2.button.Button} _close
* @property {?HTMLElement} _wrapper
* @property {?HTMLElement} _header
* @property {?HTMLElement} _appleWrapper
* @property {?HTMLElement} _frame
*/
Help4.control2.Lightbox = class extends Help4.control2.Control {
/**
* @override
* @param {Help4.control2.Lightbox.Params} [params]
*/
constructor(params) {
params ||= {};
let {size} = params;
if (size) {
if (typeof size.w !== 'number' || typeof size.h !== 'number') { // XRAY-966
size = null;
} else { // XRAY-4580
if (size.w % 2 === 1) size.w++;
if (size.h % 2 === 1) size.h++;
}
params.size = size;
}
const T = Help4.jscore.ControlBase.TYPES;
super(params, {
params: {
url: {type: T.string_null, readonly: true},
content: {type: T.string_null, readonly: true},
sizing: {type: T.string, init: 'full', readonly: true}, // full, client, explicit, explicitFull
size: {type: T.wh_null, readonly: true},
fullCover: {type: T.boolean, readonly: true},
clientArea: {type: T.xywh},
showDetach: {type: T.boolean, readonly: true},
checkboxText: {type: T.string, readonly: true},
role: {init: 'dialog'}
},
statics: {
_notAgain: {},
_detach: {},
_close: {},
_wrapper: {destroy: false},
_header: {destroy: false},
_appleWrapper: {destroy: false},
_frame: {destroy: false}
},
config: {
css: 'control-lightbox'
}
});
}
/**
* @override
* @param {HTMLElement} dom
*/
_onDomAvailable(dom) {
const {
control2: {
button: {APPEARANCES, Button, Option},
ICONS
},
Localization,
Platform: {iPad, iPhone}
} = Help4;
const {checkboxText, showDetach, url, content} = this;
const wrapper = this._createElement('div', {css: 'wrapper'});
const header = this._createElement('div', {css: 'header', dom: wrapper});
const buttons = checkboxText || showDetach
? this._createElement('div', {css: 'wrapper-buttons', dom: header})
: null;
this._wrapper = wrapper;
this._header = header;
if (checkboxText) {
this.addCss('notagain');
this._notAgain = /** @type {Help4.control2.button.Option} */ this._createControl(Option, {
dom: buttons,
text: checkboxText,
css: 'compact notagain'
})
.addListener('select', ({data: {active}}) => {
this._fireEvent({type: 'lightboxCheckbox', active});
});
}
if (showDetach) {
this._detach = /** @type {Help4.control2.button.Button} */ this._createControl(Button, {
dom: buttons,
css: 'external compact',
appearance: APPEARANCES.icon,
icon: ICONS.external,
title: Localization.getText('tooltip.detachwindow')
})
.addListener('click', () => {
Help4.windowOpen(url);
this._fireEvent({type: 'close'});
});
} else {
this.addCss('noexternal');
}
this._close = /** @type {Help4.control2.button.Button} */ this._createControl(Button, {
dom: header,
css: 'close',
appearance: APPEARANCES.icon,
icon: ICONS.close,
title: Localization.getText('tooltip.closebox')
})
.addListener('click', () => {
this._fireEvent({type: 'close'});
});
// XRAY-980: iframe needs a wrapper on apple devices
let contentDom = wrapper;
let css = 'content';
if (url && (iPad || iPhone)) {
this._appleWrapper = contentDom = this._createElement('div', {css: `${css} has-frame`, dom: wrapper});
css = 'frame'
}
this._frame = this._createElement(url ? 'iframe' : 'div', {css, src: url, html: content, dom: contentDom});
}
/**
* @override
* @param {Help4.jscore.ControlBase.PropertyChangeEvent} event
*/
_applyPropertyToDom(event) {
event.name === 'clientArea'
? _align.call(this)
: super._applyPropertyToDom(event);
}
/**
* XXX: works?
* @returns {boolean}
*/
// _handleESC() {
// this._fireEvent({type: 'close'});
// return true;
// }
}
/**
* @memberof Help4.control2.Lightbox#
* @private
*/
function _align() {
const {LIGHTBOX_SIZES: {full, explicitFull, client, explicit}} = Help4;
const {size, clientArea, fullCover, _wrapper, _appleWrapper, _frame, _header} = this;
let {sizing} = this;
const fullArea = {x: 0, y: 0, w: window.innerWidth, h: window.innerHeight};
let coverPosition; // position of cover
let wrapperPosition; // position of wrapper (lightbox within cover)
switch (sizing) {
case full:
case explicitFull:
coverPosition = wrapperPosition = fullArea;
break;
case client:
case explicit:
coverPosition = fullCover ? fullArea : clientArea;
wrapperPosition = fullCover
? {...clientArea, y: 0}
: {...clientArea, x: 0, y: 0};
break;
}
// is the lightbox big enough for requested size?
const doesFit = size && (sizing === explicitFull || sizing === explicit)
? wrapperPosition.w > size.w && wrapperPosition.h > size.h
: true;
// fallback in case size too small
if (!doesFit || wrapperPosition.w < 200 || wrapperPosition.h < 200) {
coverPosition = wrapperPosition = fullArea;
sizing = full;
}
// align cover and wrapper (box)
this.removeCss(client, explicit, full);
this.addCss(sizing === explicitFull ? explicit : sizing);
_setAreaStyle.call(this, this.getDom(), coverPosition);
_setAreaStyle.call(this, _wrapper, wrapperPosition);
const frame = _appleWrapper || _frame;
if (size && (sizing === explicit || sizing === explicitFull)) {
// manual mode: set styles with JS instead CSS
Help4.extendObject(frame.style, {width: `${size.w}px`, height: `${size.h}px`});
Help4.extendObject(_header.style, {width: `${size.w}px`, marginTop: (-size.h >> 1) + 'px'});
} else {
Help4.extendObject(frame.style, {width: null, height: null});
Help4.extendObject(_header.style, {width: null, marginTop: null});
}
}
/**
* @memberof Help4.control2.Lightbox#
* @private
* @param {HTMLElement} dom
* @param {Help4.control2.AreaXYWH} area
*/
function _setAreaStyle(dom, area) {
const map = {x: 'left', y: 'top', w: 'width', h: 'height'};
const style = {};
Object.entries(map).forEach(([areaName, styleName]) => {
style[styleName] = typeof area[areaName] === 'string' ? area[areaName] : `${area[areaName]}px`;
});
Help4.extendObject(dom.style, style);
}
})();