PHP Classes

File: assets/gallerytypes/viewerjs/src/js/methods.js

Recommend this page to a friend!
  Classes of Goffy G   wgGallery   assets/gallerytypes/viewerjs/src/js/methods.js   Download  
File: assets/gallerytypes/viewerjs/src/js/methods.js
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: wgGallery
Image gallery module for XOOPS CMS
Author: By
Last change:
Date: 3 years ago
Size: 21,789 bytes
 

Contents

Class file image Download
import { CLASS_ACTIVE, CLASS_FADE, CLASS_FIXED, CLASS_FULLSCREEN_EXIT, CLASS_HIDE, CLASS_IN, CLASS_INVISIBLE, CLASS_LOADING, CLASS_SHOW, CLASS_TRANSITION, EVENT_CLICK, EVENT_HIDE, EVENT_LOAD, EVENT_SHOW, EVENT_TRANSITION_END, EVENT_VIEW, EVENT_VIEWED, NAMESPACE, } from './constants'; import { addClass, addListener, assign, dispatchEvent, forEach, getData, getOffset, getPointersCenter, hasClass, isFunction, isNumber, isUndefined, removeClass, removeData, removeListener, setStyle, toggleClass, } from './utilities'; export default { /** Show the viewer (only available in modal mode) * @param {boolean} [immediate=false] - Indicates if show the viewer immediately or not. * @returns {Viewer} this */ show(immediate = false) { const { element, options } = this; if (options.inline || this.showing || this.isShown || this.showing) { return this; } if (!this.ready) { this.build(); if (this.ready) { this.show(immediate); } return this; } if (isFunction(options.show)) { addListener(element, EVENT_SHOW, options.show, { once: true, }); } if (dispatchEvent(element, EVENT_SHOW) === false || !this.ready) { return this; } if (this.hiding) { this.transitioning.abort(); } this.showing = true; this.open(); const { viewer } = this; removeClass(viewer, CLASS_HIDE); if (options.transition && !immediate) { const shown = this.shown.bind(this); this.transitioning = { abort() { removeListener(viewer, EVENT_TRANSITION_END, shown); removeClass(viewer, CLASS_IN); }, }; addClass(viewer, CLASS_TRANSITION); // Force reflow to enable CSS3 transition // eslint-disable-next-line viewer.offsetWidth; addListener(viewer, EVENT_TRANSITION_END, shown, { once: true, }); addClass(viewer, CLASS_IN); } else { addClass(viewer, CLASS_IN); this.shown(); } return this; }, /** * Hide the viewer (only available in modal mode) * @param {boolean} [immediate=false] - Indicates if hide the viewer immediately or not. * @returns {Viewer} this */ hide(immediate = false) { const { element, options } = this; if (options.inline || this.hiding || !(this.isShown || this.showing)) { return this; } if (isFunction(options.hide)) { addListener(element, EVENT_HIDE, options.hide, { once: true, }); } if (dispatchEvent(element, EVENT_HIDE) === false) { return this; } if (this.showing) { this.transitioning.abort(); } this.hiding = true; if (this.played) { this.stop(); } else if (this.viewing) { this.viewing.abort(); } const { viewer } = this; if (options.transition && !immediate) { const hidden = this.hidden.bind(this); const hide = () => { addListener(viewer, EVENT_TRANSITION_END, hidden, { once: true, }); removeClass(viewer, CLASS_IN); }; this.transitioning = { abort() { if (this.viewed) { removeListener(this.image, EVENT_TRANSITION_END, hide); } else { removeListener(viewer, EVENT_TRANSITION_END, hidden); } }, }; if (this.viewed) { addListener(this.image, EVENT_TRANSITION_END, hide, { once: true, }); this.zoomTo(0, false, false, true); } else { hide(); } } else { removeClass(viewer, CLASS_IN); this.hidden(); } return this; }, /** * View one of the images with image's index * @param {number} index - The index of the image to view. * @returns {Viewer} this */ view(index = 0) { index = Number(index) || 0; if (!this.isShown) { this.index = index; return this.show(); } if (this.hiding || this.played || index < 0 || index >= this.length || (this.viewed && index === this.index)) { return this; } if (this.viewing) { this.viewing.abort(); } const { element, options, title, canvas, } = this; const item = this.items[index]; const img = item.querySelector('img'); const url = getData(img, 'originalUrl'); const alt = img.getAttribute('alt'); const image = document.createElement('img'); image.src = url; image.alt = alt; if (isFunction(options.view)) { addListener(element, EVENT_VIEW, options.view, { once: true, }); } if (dispatchEvent(element, EVENT_VIEW, { originalImage: this.images[index], index, image, }) === false || !this.isShown || this.hiding || this.played) { return this; } this.image = image; removeClass(this.items[this.index], CLASS_ACTIVE); addClass(item, CLASS_ACTIVE); this.viewed = false; this.index = index; this.imageData = {}; addClass(image, CLASS_INVISIBLE); if (options.loading) { addClass(canvas, CLASS_LOADING); } canvas.innerHTML = ''; canvas.appendChild(image); // Center current item this.renderList(); // Clear title title.innerHTML = ''; // Generate title after viewed const onViewed = () => { const { imageData } = this; title.textContent = `${alt} (${imageData.naturalWidth} × ${imageData.naturalHeight})`; }; let onLoad; addListener(element, EVENT_VIEWED, onViewed, { once: true, }); this.viewing = { abort() { removeListener(element, EVENT_VIEWED, onViewed); if (image.complete) { if (this.imageRendering) { this.imageRendering.abort(); } else if (this.imageInitializing) { this.imageInitializing.abort(); } } else { removeListener(image, EVENT_LOAD, onLoad); if (this.timeout) { clearTimeout(this.timeout); } } }, }; if (image.complete) { this.load(); } else { addListener(image, EVENT_LOAD, onLoad = this.load.bind(this), { once: true, }); if (this.timeout) { clearTimeout(this.timeout); } // Make the image visible if it fails to load within 1s this.timeout = setTimeout(() => { removeClass(image, CLASS_INVISIBLE); this.timeout = false; }, 1000); } return this; }, /** * View the previous image * @param {boolean} [loop=false] - Indicate if view the last one * when it is the first one at present. * @returns {Viewer} this */ prev(loop = false) { let index = this.index - 1; if (index < 0) { index = loop ? this.length - 1 : 0; } this.view(index); return this; }, /** * View the next image * @param {boolean} [loop=false] - Indicate if view the first one * when it is the last one at present. * @returns {Viewer} this */ next(loop = false) { const maxIndex = this.length - 1; let index = this.index + 1; if (index > maxIndex) { index = loop ? 0 : maxIndex; } this.view(index); return this; }, /** * Move the image with relative offsets. * @param {number} offsetX - The relative offset distance on the x-axis. * @param {number} offsetY - The relative offset distance on the y-axis. * @returns {Viewer} this */ move(offsetX, offsetY) { const { imageData } = this; this.moveTo( isUndefined(offsetX) ? offsetX : imageData.left + Number(offsetX), isUndefined(offsetY) ? offsetY : imageData.top + Number(offsetY), ); return this; }, /** * Move the image to an absolute point. * @param {number} x - The x-axis coordinate. * @param {number} [y=x] - The y-axis coordinate. * @returns {Viewer} this */ moveTo(x, y = x) { const { imageData } = this; x = Number(x); y = Number(y); if (this.viewed && !this.played && this.options.movable) { let changed = false; if (isNumber(x)) { imageData.left = x; changed = true; } if (isNumber(y)) { imageData.top = y; changed = true; } if (changed) { this.renderImage(); } } return this; }, /** * Zoom the image with a relative ratio. * @param {number} ratio - The target ratio. * @param {boolean} [hasTooltip=false] - Indicates if it has a tooltip or not. * @param {Event} [_originalEvent=null] - The original event if any. * @returns {Viewer} this */ zoom(ratio, hasTooltip = false, _originalEvent = null) { const { imageData } = this; ratio = Number(ratio); if (ratio < 0) { ratio = 1 / (1 - ratio); } else { ratio = 1 + ratio; } this.zoomTo((imageData.width * ratio) / imageData.naturalWidth, hasTooltip, _originalEvent); return this; }, /** * Zoom the image to an absolute ratio. * @param {number} ratio - The target ratio. * @param {boolean} [hasTooltip=false] - Indicates if it has a tooltip or not. * @param {Event} [_originalEvent=null] - The original event if any. * @param {Event} [_zoomable=false] - Indicates if the current zoom is available or not. * @returns {Viewer} this */ zoomTo(ratio, hasTooltip = false, _originalEvent = null, _zoomable = false) { const { options, pointers, imageData } = this; ratio = Math.max(0, ratio); if (isNumber(ratio) && this.viewed && !this.played && (_zoomable || options.zoomable)) { if (!_zoomable) { const minZoomRatio = Math.max(0.01, options.minZoomRatio); const maxZoomRatio = Math.min(100, options.maxZoomRatio); ratio = Math.min(Math.max(ratio, minZoomRatio), maxZoomRatio); } if (_originalEvent && ratio > 0.95 && ratio < 1.05) { ratio = 1; } const newWidth = imageData.naturalWidth * ratio; const newHeight = imageData.naturalHeight * ratio; if (_originalEvent) { const offset = getOffset(this.viewer); const center = pointers && Object.keys(pointers).length ? getPointersCenter(pointers) : { pageX: _originalEvent.pageX, pageY: _originalEvent.pageY, }; // Zoom from the triggering point of the event imageData.left -= (newWidth - imageData.width) * ( ((center.pageX - offset.left) - imageData.left) / imageData.width ); imageData.top -= (newHeight - imageData.height) * ( ((center.pageY - offset.top) - imageData.top) / imageData.height ); } else { // Zoom from the center of the image imageData.left -= (newWidth - imageData.width) / 2; imageData.top -= (newHeight - imageData.height) / 2; } imageData.width = newWidth; imageData.height = newHeight; imageData.ratio = ratio; this.renderImage(); if (hasTooltip) { this.tooltip(); } } return this; }, /** * Rotate the image with a relative degree. * @param {number} degree - The rotate degree. * @returns {Viewer} this */ rotate(degree) { this.rotateTo((this.imageData.rotate || 0) + Number(degree)); return this; }, /** * Rotate the image to an absolute degree. * @param {number} degree - The rotate degree. * @returns {Viewer} this */ rotateTo(degree) { const { imageData } = this; degree = Number(degree); if (isNumber(degree) && this.viewed && !this.played && this.options.rotatable) { imageData.rotate = degree; this.renderImage(); } return this; }, /** * Scale the image on the x-axis. * @param {number} scaleX - The scale ratio on the x-axis. * @returns {Viewer} this */ scaleX(scaleX) { this.scale(scaleX, this.imageData.scaleY); return this; }, /** * Scale the image on the y-axis. * @param {number} scaleY - The scale ratio on the y-axis. * @returns {Viewer} this */ scaleY(scaleY) { this.scale(this.imageData.scaleX, scaleY); return this; }, /** * Scale the image. * @param {number} scaleX - The scale ratio on the x-axis. * @param {number} [scaleY=scaleX] - The scale ratio on the y-axis. * @returns {Viewer} this */ scale(scaleX, scaleY = scaleX) { const { imageData } = this; scaleX = Number(scaleX); scaleY = Number(scaleY); if (this.viewed && !this.played && this.options.scalable) { let changed = false; if (isNumber(scaleX)) { imageData.scaleX = scaleX; changed = true; } if (isNumber(scaleY)) { imageData.scaleY = scaleY; changed = true; } if (changed) { this.renderImage(); } } return this; }, /** * Play the images * @param {boolean} [fullscreen=false] - Indicate if request fullscreen or not. * @returns {Viewer} this */ play(fullscreen = false) { if (!this.isShown || this.played) { return this; } const { options, player } = this; const onLoad = this.loadImage.bind(this); const list = []; let total = 0; let index = 0; this.played = true; this.onLoadWhenPlay = onLoad; if (fullscreen) { this.requestFullscreen(); } addClass(player, CLASS_SHOW); forEach(this.items, (item, i) => { const img = item.querySelector('img'); const image = document.createElement('img'); image.src = getData(img, 'originalUrl'); image.alt = img.getAttribute('alt'); total += 1; addClass(image, CLASS_FADE); toggleClass(image, CLASS_TRANSITION, options.transition); if (hasClass(item, CLASS_ACTIVE)) { addClass(image, CLASS_IN); index = i; } list.push(image); addListener(image, EVENT_LOAD, onLoad, { once: true, }); player.appendChild(image); }); if (isNumber(options.interval) && options.interval > 0) { const play = () => { this.playing = setTimeout(() => { removeClass(list[index], CLASS_IN); index += 1; index = index < total ? index : 0; addClass(list[index], CLASS_IN); play(); }, options.interval); }; if (total > 1) { play(); } } return this; }, // Stop play stop() { if (!this.played) { return this; } const { player } = this; this.played = false; clearTimeout(this.playing); forEach(player.getElementsByTagName('img'), (image) => { removeListener(image, EVENT_LOAD, this.onLoadWhenPlay); }); removeClass(player, CLASS_SHOW); player.innerHTML = ''; this.exitFullscreen(); return this; }, // Enter modal mode (only available in inline mode) full() { const { options, viewer, image, list, } = this; if (!this.isShown || this.played || this.fulled || !options.inline) { return this; } this.fulled = true; this.open(); addClass(this.button, CLASS_FULLSCREEN_EXIT); if (options.transition) { removeClass(list, CLASS_TRANSITION); if (this.viewed) { removeClass(image, CLASS_TRANSITION); } } addClass(viewer, CLASS_FIXED); viewer.setAttribute('style', ''); setStyle(viewer, { zIndex: options.zIndex, }); this.initContainer(); this.viewerData = assign({}, this.containerData); this.renderList(); if (this.viewed) { this.initImage(() => { this.renderImage(() => { if (options.transition) { setTimeout(() => { addClass(image, CLASS_TRANSITION); addClass(list, CLASS_TRANSITION); }, 0); } }); }); } return this; }, // Exit modal mode (only available in inline mode) exit() { const { options, viewer, image, list, } = this; if (!this.isShown || this.played || !this.fulled || !options.inline) { return this; } this.fulled = false; this.close(); removeClass(this.button, CLASS_FULLSCREEN_EXIT); if (options.transition) { removeClass(list, CLASS_TRANSITION); if (this.viewed) { removeClass(image, CLASS_TRANSITION); } } removeClass(viewer, CLASS_FIXED); setStyle(viewer, { zIndex: options.zIndexInline, }); this.viewerData = assign({}, this.parentData); this.renderViewer(); this.renderList(); if (this.viewed) { this.initImage(() => { this.renderImage(() => { if (options.transition) { setTimeout(() => { addClass(image, CLASS_TRANSITION); addClass(list, CLASS_TRANSITION); }, 0); } }); }); } return this; }, // Show the current ratio of the image with percentage tooltip() { const { options, tooltipBox, imageData } = this; if (!this.viewed || this.played || !options.tooltip) { return this; } tooltipBox.textContent = `${Math.round(imageData.ratio * 100)}%`; if (!this.tooltipping) { if (options.transition) { if (this.fading) { dispatchEvent(tooltipBox, EVENT_TRANSITION_END); } addClass(tooltipBox, CLASS_SHOW); addClass(tooltipBox, CLASS_FADE); addClass(tooltipBox, CLASS_TRANSITION); // Force reflow to enable CSS3 transition // eslint-disable-next-line tooltipBox.offsetWidth; addClass(tooltipBox, CLASS_IN); } else { addClass(tooltipBox, CLASS_SHOW); } } else { clearTimeout(this.tooltipping); } this.tooltipping = setTimeout(() => { if (options.transition) { addListener(tooltipBox, EVENT_TRANSITION_END, () => { removeClass(tooltipBox, CLASS_SHOW); removeClass(tooltipBox, CLASS_FADE); removeClass(tooltipBox, CLASS_TRANSITION); this.fading = false; }, { once: true, }); removeClass(tooltipBox, CLASS_IN); this.fading = true; } else { removeClass(tooltipBox, CLASS_SHOW); } this.tooltipping = false; }, 1000); return this; }, // Toggle the image size between its natural size and initial size toggle() { if (this.imageData.ratio === 1) { this.zoomTo(this.initialImageData.ratio, true); } else { this.zoomTo(1, true); } return this; }, // Reset the image to its initial state reset() { if (this.viewed && !this.played) { this.imageData = assign({}, this.initialImageData); this.renderImage(); } return this; }, // Update viewer when images changed update() { const { element, options, isImg } = this; // Destroy viewer if the target image was deleted if (isImg && !element.parentNode) { return this.destroy(); } const images = []; forEach(isImg ? [element] : element.querySelectorAll('img'), (image) => { if (options.filter) { if (options.filter(image)) { images.push(image); } } else { images.push(image); } }); if (!images.length) { return this; } this.images = images; this.length = images.length; if (this.ready) { const indexes = []; forEach(this.items, (item, i) => { const img = item.querySelector('img'); const image = images[i]; if (image) { if (image.src !== img.src) { indexes.push(i); } } else { indexes.push(i); } }); setStyle(this.list, { width: 'auto', }); this.initList(); if (this.isShown) { if (this.length) { if (this.viewed) { const index = indexes.indexOf(this.index); if (index >= 0) { this.viewed = false; this.view(Math.max(this.index - (index + 1), 0)); } else { addClass(this.items[this.index], CLASS_ACTIVE); } } } else { this.image = null; this.viewed = false; this.index = 0; this.imageData = null; this.canvas.innerHTML = ''; this.title.innerHTML = ''; } } } else { this.build(); } return this; }, // Destroy the viewer destroy() { const { element, options } = this; if (!getData(element, NAMESPACE)) { return this; } this.destroyed = true; if (this.ready) { if (this.played) { this.stop(); } if (options.inline) { if (this.fulled) { this.exit(); } this.unbind(); } else if (this.isShown) { if (this.viewing) { if (this.imageRendering) { this.imageRendering.abort(); } else if (this.imageInitializing) { this.imageInitializing.abort(); } } if (this.hiding) { this.transitioning.abort(); } this.hidden(); } else if (this.showing) { this.transitioning.abort(); this.hidden(); } this.ready = false; this.viewer.parentNode.removeChild(this.viewer); } else if (options.inline) { if (this.delaying) { this.delaying.abort(); } else if (this.initializing) { this.initializing.abort(); } } if (!options.inline) { removeListener(element, EVENT_CLICK, this.onStart); } removeData(element, NAMESPACE); return this; }, };