(function() {
/**
* @typedef {Object} Help4.service.zoom.LightboxZoom.Params
* @property {Help4.controller.Controller} controller
*/
/**
* @typedef {Object} Help4.service.zoom.LightboxZoom.ZoomData
* @property {boolean} zoomed
* @property {Help4.control.Lightbox|Help4.control2.Lightbox|null} lightbox
*/
/**
* @augments Help4.jscore.ControlBase
* @property {Object} _images
*/
Help4.service.zoom.LightboxZoom = class extends Help4.jscore.ControlBase {
/**
* @override
* @param {Help4.service.zoom.LightboxZoom.Params} params
*/
constructor(params) {
const {TYPES: T} = Help4.jscore.ControlBase;
super(params, {
params: {
controller: {type: T.instance, init: null, mandatory: true, readonly: true}
},
statics: {
_images: {init: {}, destroy: false} /** see {@link Help4.service.zoom.LightboxZoom.ZoomData} */
}
});
}
/**
* transform img tag for zoom
* @param {string} input
* @returns {?string}
*/
static transform(input) {
if (input.indexOf('data-zoomable="true') < 0) return null; // zoom needs to be enabled
if (input.indexOf('zoom="inplace"') >= 0) return null; // do not interfere with in-place zoom
// add id, if missing
const id = /id="(.*?)"/.exec(input)?.[1];
if (!id) {
const newId = Help4.createId();
input = `<img id="${newId}"` + input.slice(4);
}
// add zoom-lightbox class
const css = /class="(.*?)"/.exec(input)?.[1];
let newCss = Help4.Element.createClassName('zoom-lightbox');
if (css) {
newCss = `${css} ${newCss}`;
input = input.replace(`class="${css}"`, `class="${newCss}"`);
} else {
input = `<img class="${newCss}"` + input.slice(4);
}
return input;
}
/**
* watch additional images
* @param {HTMLImageElement[]} images
* @returns {Help4.service.zoom.LightboxZoom}
*/
activate(images) {
const listener = event => _onEvent.call(this, event);
const {_images} = this;
for (const img of images) {
const {id} = img;
if (id &&
Help4.clampBoolean(img.getAttribute('data-zoomable')) &&
img.getAttribute('data-zoom') !== 'inplace') // do not interfere with in-place zoom
{
_images[id] = /** @type {Help4.service.zoom.LightboxZoom.ZoomData} */ {zoomed: false, lightbox: null};
img.addEventListener('click', listener, {passive: true});
}
}
return this;
}
/**
* update image information
* @returns {Help4.service.zoom.LightboxZoom}
*/
update() {
const {dom, dom2} = _getDom.call(this);
const {_images} = this;
for (const id of Object.keys(_images)) {
const search = `#${id}`;
if (dom.querySelector(search) || dom2?.querySelector(search)) continue;
delete _images[id];
}
return this;
}
/**
* @param {HTMLImageElement[]} removeList
* @returns {Help4.service.zoom.LightboxZoom}
*/
deactivate(removeList) {
const {_images} = this;
for (const [id, data] of Object.entries(_images)) {
for (const img of removeList) {
if (img.id === id) {
data.zoomed && _resetZoom.call(this, data);
delete _images[id];
break;
}
}
}
return this;
}
/** @returns {number} */
getCount() {
return Object.keys(this._images).length;
}
}
/**
* @memberof Help4.service.zoom.LightboxZoom#
* @private
* @returns {{dom: HTMLElement, dom2: ?HTMLElement}}
*/
function _getDom() {
const {/** @type {Help4.controller.Controller} */ controller} = this;
const dom = /** @type {HTMLElement} */ controller.getDom();
const dom2 = /** @type {?HTMLElement} */ controller.getDom2('dom');
return {dom, dom2};
}
/**
* @memberof Help4.service.zoom.LightboxZoom#
* @private
* @param {PointerEvent} event
*/
function _onEvent(event) {
const image = /** @type {HTMLImageElement} */ event.target;
const {id} = image;
const {_images} = this;
const data = id && _images[id];
if (data) {
data.zoomed
? _resetZoom.call(this, data)
: _zoom.call(this, data, image);
}
}
/**
* @memberof Help4.service.zoom.LightboxZoom#
* @private
* @param {Help4.service.zoom.LightboxZoom.ZoomData} data
* @param {HTMLImageElement} image
*/
function _zoom(data, image) {
const {controller} = this;
const lightboxService = controller.getService('lightbox');
const {core: {isActiveCMP4, isRemoteMode}} = /** @type {Help4.typedef.SystemConfiguration} */ controller.getConfiguration();
const size = {
w: image.naturalWidth,
h: image.naturalHeight
};
const content = image.outerHTML.replace(/style="[^"]*"/gi, '');
const onClose = () => _resetZoom.call(this, data);
if (isActiveCMP4) {
const widget = Help4.widget.getActiveInstance();
const name = widget?.getName();
/** @type {Help4.widget.help.view.ContentView|Help4.widget.tour.View} */ let view;
if (name === 'help' || name === 'whatsnew') {
view = /** @type {Help4.widget.help.view2.View} */ widget.getContext().widget.help.view?.getContentView();
} else if (name === 'tour') {
view = /** @type {Help4.widget.tour.View} */ widget.getContext().widget.tour.view;
}
const dom = view?.getDom();
if (!dom) return;
const {control2} = Help4;
data.zoomed = true;
data.lightbox = /** @type {Help4.control2.Lightbox} */ control2.createControl(control2.Lightbox, view, {
dom,
sizing: 'explicit',
clientArea: {x: 0, y: 0, w: window.innerWidth, h: window.innerHeight},
size,
content,
fullCover: true
})
.addListener('close', onClose);
} else {
const clientArea = isRemoteMode
? controller.getEngine('remoteControl').getContentArea()
: controller.getHandler().getContentArea();
data.zoomed = true;
data.lightbox = lightboxService.add({
sizing: 'explicit',
clientArea,
size,
content,
showDetach: false,
fullCover: true,
autoDestroy: false,
onclose: onClose,
}, 'control');
}
}
/**
* @memberof Help4.service.zoom.LightboxZoom#
* @private
* @param {Help4.service.zoom.LightboxZoom.ZoomData} data
*/
function _resetZoom(data) {
data.lightbox?.destroy();
data.lightbox = null;
data.zoomed = false;
}
})();