Source: service/zoom/ZoomService.js

(function() {
    /**
     * @namespace zoom
     * @memberof Help4.service
     */
    Help4.service.zoom = {};

    /**
     * @typedef {Object} Help4.service.zoom.ZoomService.Params
     * @property {Help4.controller.Controller} controller
     */

    /**
     * @augments Help4.service.Service
     */
    Help4.service.zoom.ZoomService = class extends Help4.service.Service {
        /**
         * @override
         * @constructor
         * @param {Help4.service.zoom.ZoomService.Params} params
         */
        constructor(params) {
            super(params, {
                controller: null
            });

            const {
                observer: {TimeObserver},
                service: {zoom: {InPlaceZoom, LightboxZoom}}
            } = Help4;

            const {_observers, _controls, _params: {controller}} = this;
            _observers.timeObserver = new TimeObserver(() => _onInterval.call(this));
            _controls.inPlace = new InPlaceZoom();
            _controls.lightbox = new LightboxZoom({controller});
        }

        /**
         * initialize zoom functionality for img tags in html
         * redirect zoom modes and transform html if necessary
         * @param {string} html
         * @returns {string}
         */
        static transform(html) {
            const {InPlaceZoom, LightboxZoom} = Help4.service.zoom;
            const regExp = /<img.*?src="(.*?)"[^>]*>/g;
            const replace = [];
            let img;

            while (img = regExp.exec(html)) {
                const t = InPlaceZoom.transform(img) || LightboxZoom.transform(img[0]);
                if (t) replace.push({original: img[0], modified: t});
            }

            for (const {original, modified} of replace) {
                html = html.replace(original, modified);
            }

            return html;
        }

        /**
         * @param {HTMLImageElement[]} images
         * @returns {Help4.service.zoom.ZoomService}
         */
        activate(images) {
            if (!images.length) return this;

            const {
                _controls: {
                    /** @type {Help4.service.zoom.InPlaceZoom} */ inPlace,
                    /** @type {Help4.service.zoom.LightboxZoom} */ lightbox
                },
                _observers: {
                    /** @type {Help4.observer.TimeObserver} */ timeObserver
                }
            } = this;

            const time = Help4.Queue.getTime() * 2;
            timeObserver.count() || timeObserver.observe('interval', {time});
            inPlace.activate(images);
            lightbox.activate(images);
            return this;
        }

        /**
         * @param {HTMLImageElement[]} images
         * @returns {Help4.service.zoom.ZoomService}
         */
        deactivate(images) {
            if (!images.length) return this;

            const {
                _controls: {
                    /** @type {Help4.service.zoom.InPlaceZoom} */ inPlace,
                    /** @type {Help4.service.zoom.LightboxZoom} */ lightbox
                },
                _observers: {
                    /** @type {Help4.observer.TimeObserver} */ timeObserver
                }
            } = this;

            inPlace.deactivate(images);
            lightbox.deactivate(images);

            if (!inPlace.getCount() && !lightbox.getCount()) {
                timeObserver.disconnect();
            }
            return this;
        }
    }

    /**
     * @memberof Help4.service.zoom.ZoomService#
     * @private
     */
    function _onInterval() {
        const {
            _controls: {
                /** @type {Help4.service.zoom.InPlaceZoom} */ inPlace,
                /** @type {Help4.service.zoom.LightboxZoom} */ lightbox
            },
            _observers: {
                /** @type {Help4.observer.TimeObserver} */ timeObserver
            }
        } = this;

        inPlace.update();
        lightbox.update();

        if (!inPlace.getCount() && !lightbox.getCount()) {
            timeObserver.disconnect();
        }
    }
})();