Files
roi-theme/wp-content/plugins/ajax-search-pro/js/nomin/external/photostack.js
root a22573bf0b Commit inicial - WordPress Análisis de Precios Unitarios
- WordPress core y plugins
- Tema Twenty Twenty-Four configurado
- Plugin allow-unfiltered-html.php simplificado
- .gitignore configurado para excluir wp-config.php y uploads

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 21:04:30 -06:00

413 lines
17 KiB
JavaScript
Executable File

/**
* photostack.js v1.0.0 (modified version)
* original from: http://www.codrops.com
*
* Licensed under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright 2014, Codrops
* http://www.codrops.com
*/
(function(){
'use strict';
function extend( a, b ) {
for( let key in b ) {
if( b.hasOwnProperty( key ) ) {
a[key] = b[key];
}
}
return a;
}
function shuffleMArray( marray ) {
if (typeof marray == "undefined" || typeof marray[0] == "undefined")
return false;
let arr = [], marrlen = marray.length, inArrLen = marray[0].length;
for(let i = 0; i < marrlen; i++) {
arr = arr.concat( marray[i] );
}
// shuffle 2 d array
arr = shuffleArr( arr );
// to 2d
let newmarr = [], pos = 0;
for( let j = 0; j < marrlen; j++ ) {
let tmparr = [];
for( let k = 0; k < inArrLen; k++ ) {
tmparr.push( arr[ pos ] );
pos++;
}
newmarr.push( tmparr );
}
return newmarr;
}
function shuffleArr( array ) {
let m = array.length, t, i;
// While there remain elements to shuffle…
while (m) {
// Pick a remaining element…
i = Math.floor(Math.random() * m--);
// And swap it with the current element.
t = array[m];
array[m] = array[i];
array[i] = t;
}
return array;
}
function Photostack( el, options ) {
this.el = el;
this.inner = this.el.querySelector( 'div' );
this.allItems = [].slice.call( this.inner.children );
this.allItemsCount = this.allItems.length;
if( !this.allItemsCount ) return;
this.items = [].slice.call( this.inner.querySelectorAll( 'figure:not([data-dummy])' ) );
this.itemsCount = this.items.length;
// index of the current photo
this.current = 0;
this.options = extend( {}, this.options );
extend( this.options, options );
this._init();
}
Photostack.prototype.options = {};
Photostack.prototype._init = function() {
this.currentItem = this.items[ this.current ];
this._addNavigation();
this._getSizes();
this._initEvents();
}
Photostack.prototype._addNavigation = function() {
// add nav dots
this.nav = document.createElement( 'nav' )
let inner = '';
for( let i = 0; i < this.itemsCount; ++i ) {
inner += '<span></span>';
}
this.nav.innerHTML = inner;
this.el.appendChild( this.nav );
this.navDots = [].slice.call( this.nav.children );
}
Photostack.prototype._initEvents = function() {
let self = this,
beforeStep = this.el.classList.contains( 'photostack-start' ),
open = function() {
let setTransition = function() {
self.el.classList.add( 'photostack-transition' );
}
if( beforeStep ) {
this.removeEventListener( 'click', open );
self.el.classList.remove( 'photostack-start' );
setTransition();
}
else {
self.openDefault = true;
setTimeout( setTransition, 25 );
}
self.started = true;
self._showPhoto( self.current );
};
if( beforeStep ) {
this._shuffle();
this.el.addEventListener( 'click', open );
}
else {
open();
}
this.navDots.forEach( function( dot, idx ) {
dot.addEventListener( 'click', function() {
// rotate the photo if clicking on the current dot
if( idx === self.current ) {
self._rotateItem();
}
else {
// if the photo is flipped then rotate it back before shuffling again
let callback = function() { self._showPhoto( idx ); }
if( self.flipped ) {
self._rotateItem( callback );
}
else {
callback();
}
}
} );
} );
// This triggers an error message..
//window.addEventListener( 'resize', function() { self._resizeHandler(); } );
}
Photostack.prototype._resizeHandler = function() {
let self = this;
function delayed() {
self._resize();
self._resizeTimeout = null;
}
if ( this._resizeTimeout ) {
clearTimeout( this._resizeTimeout );
}
this._resizeTimeout = setTimeout( delayed, 100 );
}
Photostack.prototype._resize = function() {
let self = this, callback = function() { self._shuffle( true ); }
this._getSizes();
if( this.started && this.flipped ) {
this._rotateItem( callback );
}
else {
callback();
}
}
Photostack.prototype._showPhoto = function( pos ) {
if( this.isShuffling ) {
return false;
}
this.isShuffling = true;
// if there is something behind..
if( this.currentItem.classList.contains( 'photostack-flip' ) ) {
this._removeItemPerspective();
this.navDots[ this.current ].classList.remove( 'flippable' );
}
this.navDots[ this.current ].classList.remove( 'current' );
this.currentItem.classList.remove( 'photostack-current' );
// change current
this.current = pos;
this.currentItem = this.items[ this.current ];
this.navDots[ this.current ].classList.add( 'current' );
// if there is something behind..
if( this.currentItem.querySelector( '.photostack-back' ) ) {
// nav dot gets class flippable
this.navDots[ pos ].classList.add( 'flippable' );
}
// shuffle a bit
this._shuffle();
}
// display items (randomly)
// noinspection JSMismatchedCollectionQueryUpdate
Photostack.prototype._shuffle = function( resize ) {
let iter = resize ? 1 : this.currentItem.getAttribute( 'data-shuffle-iteration' ) || 1;
if( iter <= 0 || !this.started || this.openDefault ) { iter = 1; }
// first item is open by default
if( this.openDefault ) {
// change transform-origin
this.currentItem.classList.add( 'photostack-flip' );
this.openDefault = false;
this.isShuffling = false;
}
let overlapFactor = .5,
// lines & columns
lines = Math.ceil(this.sizes.inner.width / (this.sizes.item.width * overlapFactor) ),
columns = Math.ceil(this.sizes.inner.height / (this.sizes.item.height * overlapFactor) ),
// since we are rounding up the previous calcs we need to know how much more we are adding to the calcs for both x and y axis
addX = lines * this.sizes.item.width * overlapFactor + this.sizes.item.width/2 - this.sizes.inner.width,
addY = columns * this.sizes.item.height * overlapFactor + this.sizes.item.height/2 - this.sizes.inner.height,
// we will want to center the grid
extraX = addX / 2,
extraY = addY / 2,
// max and min rotation angles
maxrot = 35, minrot = -35,
self = this,
// translate/rotate items
moveItems = function() {
--iter;
// create a "grid" of possible positions
let grid = [];
// populate the positions grid
for( let i = 0; i < columns; ++i ) {
// noinspection JSMismatchedCollectionQueryUpdate
let col = grid[ i ] = [];
for( let j = 0; j < lines; ++j ) {
let xVal = j * (self.sizes.item.width * overlapFactor) - extraX,
yVal = i * (self.sizes.item.height * overlapFactor) - extraY,
olx = 0, oly = 0;
if( self.started && iter === 0 ) {
let ol = self._isOverlapping( { x : xVal, y : yVal } );
if( ol.overlapping ) {
olx = ol.noOverlap.x;
oly = ol.noOverlap.y;
let r = Math.floor( Math.random() * 3 );
switch(r) {
case 0 : olx = 0; break;
case 1 : oly = 0; break;
}
}
}
col[ j ] = { x : xVal + olx, y : yVal + oly };
}
}
// shuffle
grid = shuffleMArray(grid);
let l = 0, c = 0, cntItemsAnim = 0;
self.allItems.forEach( function( item ) {
// pick a random item from the grid
if( l === lines - 1 ) {
c = c === columns - 1 ? 0 : c + 1;
l = 1;
}
else {
++l
}
let gridVal = grid[c][l-1],
translation = { x : gridVal.x, y : gridVal.y },
onEndTransitionFn = function() {
++cntItemsAnim;
this.removeEventListener( 'transitionend', onEndTransitionFn );
// noinspection JSIncompatibleTypesComparison
if( cntItemsAnim === self.allItemsCount ) {
if( iter > 0 ) {
moveItems.call();
}
else {
// change transform-origin
self.currentItem.classList.add( 'photostack-flip' );
// all done..
self.isShuffling = false;
if( typeof self.options.callback === 'function' ) {
self.options.callback( self.currentItem );
}
}
}
};
if(self.items.indexOf(item) === self.current && self.started && iter === 0) {
self.currentItem.style.WebkitTransform = 'translate(' + self.centerItem.x + 'px,' + self.centerItem.y + 'px) rotate(0deg)';
self.currentItem.style.msTransform = 'translate(' + self.centerItem.x + 'px,' + self.centerItem.y + 'px) rotate(0deg)';
self.currentItem.style.transform = 'translate(' + self.centerItem.x + 'px,' + self.centerItem.y + 'px) rotate(0deg)';
// if there is something behind..
if( self.currentItem.querySelector( '.photostack-back' ) ) {
self._addItemPerspective();
}
self.currentItem.classList.add( 'photostack-current' );
}
else {
item.style.WebkitTransform = 'translate(' + translation.x + 'px,' + translation.y + 'px) rotate(' + Math.floor( Math.random() * (maxrot - minrot + 1) + minrot ) + 'deg)';
item.style.msTransform = 'translate(' + translation.x + 'px,' + translation.y + 'px) rotate(' + Math.floor( Math.random() * (maxrot - minrot + 1) + minrot ) + 'deg)';
item.style.transform = 'translate(' + translation.x + 'px,' + translation.y + 'px) rotate(' + Math.floor( Math.random() * (maxrot - minrot + 1) + minrot ) + 'deg)';
}
if( self.started ) {
item.addEventListener( 'transitionend', onEndTransitionFn );
}
} );
};
moveItems.call();
}
Photostack.prototype._getSizes = function() {
this.sizes = {
inner : { width : this.inner.offsetWidth, height : this.inner.offsetHeight },
item : { width : this.currentItem.offsetWidth, height : this.currentItem.offsetHeight }
};
// translation values to center an item
this.centerItem = { x : this.sizes.inner.width / 2 - this.sizes.item.width / 2, y : this.sizes.inner.height / 2 - this.sizes.item.height / 2 };
}
Photostack.prototype._isOverlapping = function( itemVal ) {
let dxArea = this.sizes.item.width + this.sizes.item.width / 3, // adding some extra avoids any rotated item to touch the central area
dyArea = this.sizes.item.height + this.sizes.item.height / 3,
areaVal = { x : this.sizes.inner.width / 2 - dxArea / 2, y : this.sizes.inner.height / 2 - dyArea / 2 },
dxItem = this.sizes.item.width,
dyItem = this.sizes.item.height;
if( !(( itemVal.x + dxItem ) < areaVal.x ||
itemVal.x > ( areaVal.x + dxArea ) ||
( itemVal.y + dyItem ) < areaVal.y ||
itemVal.y > ( areaVal.y + dyArea )) ) {
// how much to move so it does not overlap?
// move left / or move right
let left = Math.random() < 0.5,
randExtraX = Math.floor( Math.random() * (dxItem/4 + 1) ),
randExtraY = Math.floor( Math.random() * (dyItem/4 + 1) ),
noOverlapX = left ? (itemVal.x - areaVal.x + dxItem) * -1 - randExtraX : (areaVal.x + dxArea) - (itemVal.x + dxItem) + dxItem + randExtraX,
noOverlapY = left ? (itemVal.y - areaVal.y + dyItem) * -1 - randExtraY : (areaVal.y + dyArea) - (itemVal.y + dyItem) + dyItem + randExtraY;
return {
overlapping : true,
noOverlap : { x : noOverlapX, y : noOverlapY }
}
}
return {
overlapping : false
}
}
Photostack.prototype._addItemPerspective = function() {
this.el.classList.add( 'photostack-perspective' );
}
Photostack.prototype._removeItemPerspective = function() {
this.el.classList.remove( 'photostack-perspective' );
this.currentItem.classList.remove( 'photostack-flip' );
}
Photostack.prototype._rotateItem = function( callback ) {
if( this.el.classList.contains( 'photostack-perspective' ) && !this.isRotating && !this.isShuffling ) {
this.isRotating = true;
let self = this, onEndTransitionFn = function() {
this.removeEventListener( 'transitionend', onEndTransitionFn );
self.isRotating = false;
if( typeof callback === 'function' ) {
callback();
}
};
if( this.flipped ) {
this.navDots[ this.current ].classList.remove( 'flip' );
this.currentItem.style.WebkitTransform = 'translate(' + this.centerItem.x + 'px,' + this.centerItem.y + 'px) rotateY(0deg)';
this.currentItem.style.transform = 'translate(' + this.centerItem.x + 'px,' + this.centerItem.y + 'px) rotateY(0deg)';
}
else {
this.navDots[ this.current ].classList.add( 'flip' );
this.currentItem.style.WebkitTransform = 'translate(' + this.centerItem.x + 'px,' + this.centerItem.y + 'px) translate(' + this.sizes.item.width + 'px) rotateY(-179.9deg)';
this.currentItem.style.transform = 'translate(' + this.centerItem.x + 'px,' + this.centerItem.y + 'px) translate(' + this.sizes.item.width + 'px) rotateY(-179.9deg)';
}
this.flipped = !this.flipped;
this.currentItem.addEventListener( 'transitionend', onEndTransitionFn );
this.currentItem.addEventListener( 'transitionstart' , function handler(event) {
// Get the transition duration (in seconds)
const style = getComputedStyle(self.currentItem);
const duration = parseFloat(style.transitionDuration) * 1000; // Convert to ms
// Calculate halfway point
const halfway = duration / 2;
// Trigger callback at halfway point
setTimeout(() => {
if ( self.flipped ) {
self.currentItem.classList.add('photostack-flipped');
} else {
self.currentItem.classList.remove('photostack-flipped');
}
}, halfway);
// Remove the event listener to prevent multiple triggers
self.currentItem.removeEventListener('transitionstart', handler);
});
}
}
// add to global namespace
window.Photostack = Photostack;
}());