1class BlockCustomizer { 2 constructor(block) { 3 frontendSetLazyContent(block.get(0)); 4 setVideoBackground(block); 5 6 if (block.find('.block-scroll-effect-fixed').each((index, element) => { 7 new BlockCustomizerItemsFixed($(element)); 8 })); 9 10 if (block.find('.block-scroll-effect-parallax').each((index, element) => { 11 new BlockCustomizerItemsParallax(index, $(element)); 12 })); 13 14 if (block.find('.block-scroll-effect-scale').each((index, element) => { 15 new BlockCustomizerItemsScale(index, $(element)); 16 })); 17 18 if (block.find('.block-scroll-effect-scale-inv').each((index, element) => { 19 new BlockCustomizerItemsScaleInv(index, $(element)); 20 })); 21 22 if (block.find('.block-mousemove-effect-opposite').each((index, element) => { 23 new BlockCustomizerItemsMouseMoveOpposite($(element)); 24 })); 25 26 if (block.find('.block-mousemove-effect-follow').each((index, element) => { 27 new BlockCustomizerItemsMouseMoveFollow($(element)); 28 })); 29 30 if (block.find('[data-width-option="screen-adaptive"]').each((index, element) => { 31 new BlockCustomizerItemsFullWidth($(element)); 32 })); 33 34 if (block.find('[data-height-option="content-adaptive"]').each((index, element) => { 35 new BlockCustomizerItemsAutoHeight($(element)); 36 })); 37 38 new BlockCustomizerContainerHeight(block); 39 BlockCustomizerItemsBackgroundClip.addBlock(block); 40 } 41} 42 43// No usamos esta clase porque se ha desactivado el ancho máximo para el .container 44class BlockCustomizerCssVars { 45 constructor(block) { 46 const wrapper = $('#wrapper'); 47 48 // Solo aplicable a proyectos con un ancho grande y relativo 49 if (!wrapper.hasClass('size-lg') && !wrapper.hasClass('size-xl')) 50 return; 51 52 this.block = block; 53 this.varBlockCustomizerItemSizeFixed = '--block-customizer-item-size-fixed'; 54 this.cssBlockCustomizerItemSizeFixed = getComputedStyle(document.documentElement).getPropertyValue(this.var).trim(); 55 56 this.updateVars(); 57 58 $(window).on('resize', e => { 59 this.updateVars(); 60 }); 61 } 62 63 updateVars() { 64 const container = this.block.find('.container'); 65 const maxContainerWidth = 1920; 66 67 if (container.outerWidth() >= maxContainerWidth) { 68 document.documentElement.style.setProperty(this.varBlockCustomizerItemSizeFixed, '7.44px'); 69 } else { 70 document.documentElement.style.setProperty(this.varBlockCustomizerItemSizeFixed, this.cssBlockCustomizerItemSizeFixed); 71 } 72 } 73} 74 75class BlockCustomizerItemsFixed { 76 constructor(element) { 77 78 this.element = element; 79 this.parent = element.parents('.block.block-customizer'); 80 this.builderTopBarHeight = (_APP.builder ? $('#builder-header').outerHeight() : 0); 81 82 this.element.attr('data-offset-top', this.element.offset().top); 83 84 $(window).on('scroll', e => { 85 this._updatePosition(); 86 }); 87 88 $(window).on('load', e => { 89 this._updatePosition(); 90 this._updateElementOffsetTop(); 91 }); 92 93 $(window).on('resize', e => { 94 this._updatePosition(); 95 this._updateElementOffsetTop(); 96 }); 97 98 const obsResize = new ResizeObserver(entries => { 99 this._updatePosition(); 100 this._updateElementOffsetTop(); 101 }); 102 103 obsResize.observe(document.body); 104 } 105 106 _getTransformScaleValue(element) { 107 let matrix = element.css('transform'); 108 let scale = 1; // Valor por defecto si no hay transformación 109 110 if (matrix !== 'none') { 111 let v = matrix.split('(')[1].split(')')[0].split(','); 112 // Math.hypot(v[0], v[1]) extrae la escala real combinada 113 scale = Math.hypot(v[0], v[1]); 114 } 115 116 return scale; 117 } 118 119 // Obtenemos el left del elemento respecto a su contenedor 120 _getRealCssLeft(element) { 121 return parseInt(element.css('left')); 122 } 123 124 _updatePosition() { 125 const builderHeaderBarHeight = (_APP.builder ? $('#builder-header').height() : 0); 126 const scrollY = window.scrollY; 127 const parentOffsetTop = this.parent.offset().top; 128 const elementTop = parseInt(this.element.attr('data-offset-top')) - parseInt(this.parent.offset().top); 129 const parentEnd = (this.parent.offset().top + this.parent.outerHeight()) - scrollY; 130 const scrollYLimit = parentEnd - (this.element.outerHeight() + elementTop * 2); 131 const elementBorderWidth = parseInt(this.element.css('border-width')); 132 let width; 133 let height; 134 135 // Debido a un problema que al cambiar de position absolute a fixed, si el tamaño se adapta al contenido, 136 // el tamaño del elemento puede cambiar, por lo que tenemos que guardar el tamaño antes de pasar a position fixed 137 // Además, lo guardamos en un atributo para poder usarlo luego 138 // Al cambiar de position absolute a fixed, a veces aparecen problemas 139 // - Si el tamaño se adapta al contenido 140 // - Si hay animaciones en el proyecto, el offset.left no funciona correctamente 141 if (this.element.css('position') == 'absolute') { 142 143 // El ancho lo guardamos cuando el ancho deba adaptarse al contenido y ... 144 // cuando esté configurado en el diseño, esto es porque en el móvil da problemas y da un salto (ya que son unidades relativas) 145 if (this.element.attr('data-width-option') == 'content-adaptive' || this.element.attr('data-width-option') == 'none') 146 this.element.attr('data-content-inner-width', this.element.find('.content').innerWidth() + elementBorderWidth + 1); 147 148 // Solo guardamos el alto cuando el alto deba adaptarse al contenido 149 if (this.element.attr('data-height-option') == 'content-adaptive') 150 this.element.attr('data-content-inner-height', this.element.find('.content').innerHeight() + elementBorderWidth + 1); 151 152 // Guardamos el left para su posterior uso 153 this.element.attr('data-offset-left', this._getRealCssLeft(this.element) + this.element.parents('.block-customizer-grid').offset().left); 154 } 155 156 // El scroll está dentro del bloque, lo fijamos 157 if (scrollY >= parentOffsetTop - builderHeaderBarHeight && scrollYLimit >= 0) { 158 this.element.css({ 159 position: 'fixed', 160 top: elementTop + builderHeaderBarHeight, 161 left: parseInt(this.element.attr('data-offset-left')), 162 bottom: '', 163 }); 164 165 // Si el atributo tiene el tamaño del contenido lo establecemos como important 166 if (width = this.element.attr('data-content-inner-width')) 167 this.element.get(0).style.setProperty('width', width + 'px', 'important'); 168 169 if (height = this.element.attr('data-content-inner-height')) 170 this.element.get(0).style.setProperty('height', height + 'px', 'important'); 171 172 } 173 // El scroll no ha llegado al bloque, desactivamos estilos 174 else if (scrollY <= parentOffsetTop) { 175 this.element.css({ 176 position: '', 177 top: '', 178 left: '', 179 bottom: '', 180 width: '', 181 height: '', 182 }); 183 } 184 // El scroll está en el lÃmite, fijamos el elemento al final del bloque 185 else if (scrollYLimit < 0) { 186 this.element.css({ 187 position: 'absolute', 188 top: 'unset', 189 left: '', 190 bottom: elementTop - builderHeaderBarHeight, 191 width: '', 192 height: '', 193 }); 194 } 195 196 BlockCustomizerItemsAutoHeight.forceUpdateHeight(this.element); 197 BlockCustomizerItemsFullWidth.forceUpdateWidth(this.element); 198 } 199 200 _updateElementOffsetTop() { 201 const position = this.element.css('position'); 202 const top = this.element.css('top'); 203 const left = this.element.css('left'); 204 const bottom = this.element.css('bottom'); 205 206 this.element.css({ 207 position: '', 208 top: '', 209 left: '', 210 bottom: '', 211 }); 212 213 this.element.attr('data-offset-top', this.element.offset().top); 214 215 this.element.css({ 216 position: position, 217 top: top, 218 left: left, 219 bottom: bottom, 220 }); 221 } 222} 223 224class BlockCustomizerItemsParallax { 225 constructor(index, element) { 226 this.element = $(element); 227 this.parent = this.element.parent(); 228 this.step = 0.3; 229 this.margin = -150; // Margen de seguridad 230 231 // Guardamos la posición inicial de diseño (CSS) 232 this.initialElementTop = parseInt(this.element.css('top')) || 0; 233 234 setTimeout(() => this._init(), 350); 235 } 236 237 _init() { 238 $(window).on('scroll.parallax', () => this._onScroll()) 239 .trigger('scroll.parallax'); 240 } 241 242 _onScroll() { 243 const windowHeight = $(window).height(); 244 const scrollTop = $(window).scrollTop(); 245 246 const parentOffsetTop = this.parent.offset().top; 247 const parentHeight = this.parent.outerHeight(); 248 249 // Punto de activación: cuando el borde superior del padre entra por abajo 250 const startPoint = parentOffsetTop - windowHeight - this.margin + this.initialElementTop; 251 // Punto de finalización: cuando el borde inferior sale por arriba 252 const endPoint = parentOffsetTop + parentHeight; 253 254 if (scrollTop <= startPoint) { 255 // Antes de entrar en la zona: mantenemos el top inicial 256 this._animate(this.initialElementTop); 257 return; 258 } 259 260 if (scrollTop >= endPoint) { 261 // Después de la zona: clamp al valor máximo calculado en endPoint 262 const relativeScrollMax = endPoint - startPoint; 263 this._animate(this.initialElementTop + (relativeScrollMax * this.step)); 264 return; 265 } 266
267 // Dentro de la zona: el desplazamiento 0 es justo en startPoint 268 const relativeScroll = scrollTop - startPoint; 269 270 this._animate(this.initialElementTop + (relativeScroll * this.step)); 271 } 272 273 _animate(top) { 274 anime({ 275 targets: this.element.get(0), 276 top: top, 277 duration: 10, 278 easing: 'linear' 279 }); 280 } 281} 282 283class BlockCustomizerItemsParallax__NO { 284 constructor(index, element) { 285 this.element = $(element); 286 this.parent = this.element.parent(); 287 this.step = 0.2 + (index * 0.15); 288 this.margin = 20; 289 290 // Guardamos la posición inicial de diseño (CSS) 291 this.initialTop = parseInt(this.element.css('top')) || 0; 292 293 setTimeout(() => this._init(), 1100); 294 } 295 296 _init() { 297 $(window).on('scroll.parallax', () => this._onScroll()) 298 .trigger('scroll.parallax'); 299 } 300 301 _onScroll() { 302 const windowHeight = $(window).height(); 303 const elementHeight = this.element.outerHeight(); 304 const elementTop = parseInt(this.element.css('top')); 305 const scrollTop = $(window).scrollTop(); 306 307 // Posición del padre respecto al documento 308 const parentOffsetTop = this.parent.offset().top; 309 const parentHeight = this.parent.outerHeight(); 310 311 // Punto de activación: cuando el borde superior del padre entra por abajo 312 const startPoint = parentOffsetTop - windowHeight - this.margin + elementTop; 313 // Punto de finalización: cuando el borde inferior sale por arriba 314 const endPoint = parentOffsetTop + parentHeight - elementHeight * 2; 315 316 if (scrollTop > startPoint && scrollTop < endPoint) { 317 // Calculamos cuánto ha avanzado el scroll dentro de la "zona del padre" 318 // El desplazamiento 0 será justo cuando el padre empieza a asomar 319 const relativeScroll = scrollTop - parentOffsetTop; 320 321 const offset = Math.max(scrollTop - parentOffsetTop + this.initialTop, 0) * 1.3; 322 323 this.element.css('transform', 'translateY(' + offset + 'px)'); 324 325 //this._animate(this.initialTop + offset); 326 327 console.log('Animando..', this.initialTop, offset) 328 } 329 } 330 331 _animate(top) { 332 anime({ 333 targets: this.element.get(0), 334 top: top, 335 duration: 10, 336 easing: 'linear' // Para parallax es mejor linear o un ease muy suave 337 }); 338 } 339} 340 341class BlockCustomizerItemsScale { 342 constructor(index, element) { 343 344 if (element.find('.block-background-image-parallax').length) { 345 element.find('.block-background-image-parallax').addClass('with-scale-effect'); 346 } 347 348 $(window).on('scroll', e => { 349 const blockOffsetTop = element.parents('.block-customizer').offset().top; 350 const blockHeight = element.parents('.block-customizer').outerHeight(); 351 const scrollTop = $(window).scrollTop(); 352 const windowHeight = $(window).height(); 353 const maxValue = 125; 354 const start = blockOffsetTop; 355 const end = blockOffsetTop + blockHeight; 356 const total = (end - start) / 100; 357 const current = ((scrollTop + windowHeight) - blockOffsetTop) / 100; 358 let value = 0; 359 360 if (scrollTop + windowHeight > blockOffsetTop && scrollTop + windowHeight <= blockOffsetTop + blockHeight) { 361 value = (maxValue * current) / total; 362 363 element.css('transform', 'scale(' + (value / 100) + ')'); 364 } 365 }).scroll(); 366 } 367} 368 369class BlockCustomizerItemsScaleInv { 370 constructor(index, element) { 371 372 if (element.find('.block-background-image-parallax').length) { 373 element.find('.block-background-image-parallax').addClass('with-scale-effect'); 374 } 375 376 $(window).on('scroll', e => { 377 const blockOffsetTop = element.parents('.block-customizer').offset().top; 378 const blockHeight = element.parents('.block-customizer').outerHeight(); 379 const scrollTop = $(window).scrollTop(); 380 const windowHeight = $(window).height(); 381 const maxValue = 400; 382 const start = blockOffsetTop; 383 const end = blockOffsetTop + blockHeight * 1.3; 384 const total = (end - start) / 100; 385 let current = ((scrollTop + windowHeight) - blockOffsetTop) / 100; 386 let value = 0; 387 388 if (scrollTop + windowHeight > blockOffsetTop && scrollTop + windowHeight <= blockOffsetTop + blockHeight) { 389 let scale = 1; 390 current = (total - current); 391 value = (maxValue * current) / total; 392 393 scale = (value / 100); 394 395 if (scale < 1) 396 scale = 1; 397 398 element.css('transform', 'scale(' + scale + ')'); 399 } 400 }).scroll(); 401 } 402} 403 404class BlockCustomizerContainerHeight { 405 constructor(block) { 406 this.block = block; 407 408 this.setGridHeightAuto(); 409 410 $(window).on('resize', e => { 411 this.setGridHeightAuto(); 412 }); 413 } 414 415 setGridHeightAuto() { 416 // Estos valores se encuentran en block-customizer-backend.css y deben coincidir 417 const fakeDesktopContainerWidthLG = 1302; 418 const fakeDesktopContainerWidthXL = 1502; 419 const fakeMobileContainerWidth = 402; 420 421 const wrapper = $('#wrapper'); 422 const grid = this.block.find('.block-customizer-grid'); 423 let gridHeight = parseInt(grid.css('height'));
424 const wrapperWidth = wrapper.outerWidth() - ($('body').hasClass('builder') ? 50 : 0); 425 let fakeContainerWidth = 0; 426 let newHeight = 0; 427 428 // Solo aplicable a proyectos con un ancho grande y relativo 429 if (!wrapper.hasClass('size-lg') && !wrapper.hasClass('size-xl')) 430 return; 431 432 if (!grid.attr('data-height')) 433 grid.attr('data-height', gridHeight); 434 else 435 gridHeight = parseInt(grid.attr('data-height')); 436 437 if (isSmallScreen()) { 438 fakeContainerWidth = fakeMobileContainerWidth; 439 } else { 440 fakeContainerWidth = (wrapper.hasClass('size-lg') ? fakeDesktopContainerWidthLG : fakeDesktopContainerWidthXL); 441 } 442 443 newHeight = ((wrapperWidth * gridHeight) / fakeContainerWidth); 444 445 // NOTA: desactivamos este código porque está estirando la altura del grid hasta mostrar todos los items 446 // Esto es un problema puesto que hay veces que se quiere dejar parcialmente fuera del grid un elemento 447 // Buscamos el bloque que está más abajo del todo para establecer la nueva altura del grid 448 /* 449 this.block.find('.block-customizer-item').each((index, element) => { 450 element = $(element); 451 452 let value = parseInt(element.css('top')) + element.outerHeight(); 453 454 if (value > newHeight) 455 newHeight = value + 15; 456 }); 457 */ 458 459 // Configuramos la nueva altura del grid 460 if (newHeight > 0) 461 grid.css('height', newHeight); 462 } 463} 464 465class BlockCustomizerItemsBackgroundClip { 466 467 static addBlock(block) { 468 block.find('.block-customizer-item[data-bg-clip="true"]').each((index, element) => { 469 BlockCustomizerItemsBackgroundClip.addItemStyles($(element)); 470 }); 471 } 472 473 static addItemStyles(item) { 474 475 if (item.attr('data-bg-clip') != 'true') { 476 return false; 477 } 478 479 const bgImage = item.find('.block-background-image img'); 480 const src = (bgImage.attr('src') != undefined ? bgImage.attr('src') : bgImage.attr('data-src')); 481 482 if (src == undefined) { 483 item.find('.content').css({ 484 'background-color': item.css('background-color'), 485 }); 486 } 487 else { 488 item.find('.content').css({ 489 'background-image': 'url(' + src + ')', 490 }); 491 } 492 493 item.css('background-color', 'transparent'); 494 } 495} 496 497class BlockCustomizerItemsMouseMoveOpposite { 498 constructor(element) { 499 500 element = element.get(0); 501 502 document.addEventListener('mousemove', (e) => { 503 const { clientX, clientY } = e; 504 const { innerWidth, innerHeight } = window; 505 506 const offsetX = (clientX - innerWidth / 2) * -0.05; 507 const offsetY = (clientY - innerHeight / 2) * -0.05; 508 509 anime({ 510 targets: element, 511 translateX: offsetX, 512 translateY: offsetY, 513 duration: 500, 514 easing: 'easeOutQuad' 515 }); 516 }); 517 } 518} 519 520class BlockCustomizerItemsMouseMoveFollow { 521 constructor(element) { 522 523 element = element.get(0); 524 525 document.addEventListener('mousemove', (e) => { 526 const { clientX, clientY } = e; 527 const { innerWidth, innerHeight } = window; 528 529 const offsetX = (clientX - innerWidth / 2) * 0.1; 530 const offsetY = (clientY - innerHeight / 2) * 0.1; 531 532 anime({ 533 targets: element, 534 translateX: offsetX, 535 translateY: offsetY, 536 duration: 500, 537 easing: 'easeOutQuad' 538 }); 539 }); 540 } 541} 542 543class BlockCustomizerItemsFullWidth { 544 constructor(element) { 545 if (element.attr('data-width-option') != 'screen-adaptive') 546 return; 547 548 this.element = element; 549 550 function isInViewport(element) { 551 const rect = element.getBoundingClientRect(); 552 return ( 553 rect.top >= 0 && 554 rect.left >= 0 && 555 rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && 556 rect.right <= (window.innerWidth || document.documentElement.clientWidth) 557 ); 558 } 559 560 $(window).resize(e => { 561 this._updateLeft(); 562 }); 563 564 this._updateLeft(); 565 566 if (isInViewport(this.element.get(0))) { 567 setTimeout(() => { 568 this._updateLeft(); 569 }, 300); 570 } 571 } 572 573 _updateLeft() { 574 BlockCustomizerItemsFullWidth.forceUpdateWidth(this.element); 575 } 576 577 static forceUpdateWidth(element) { 578 if (element.attr('data-width-option') != 'screen-adaptive') 579 return; 580 581 const parent = element.parents('.block.block-customizer'); 582 const container = parent.find('.container'); 583 const builderMenuWidth = (_APP.builder ? $('#builder-menu').outerWidth() : 0); 584 let left = 0; 585 586 if (element.offset().left == 0) { 587 left = builderMenuWidth; 588 } else { 589 left = builderMenuWidth - parseInt(container.css('padding-left')) + container.offset().left * -1; 590 } 591 592 element.get(0).style.setProperty('left', parseInt(left) + 'px', 'important'); 593 } 594} 595 596class BlockCustomizerItemsAutoHeight { 597 constructor(element) { 598 if (element.attr('data-height-option') != 'content-adaptive') 599 return; 600 601 this.element = element; 602 603 $(window).resize(e => { 604 this._updateHeight(); 605 }); 606 607 this._updateHeight(); 608 } 609 610 _updateHeight() { 611 BlockCustomizerItemsAutoHeight.forceUpdateHeight(this.element); 612 } 613 614 static forceUpdateHeight(element) { 615 if (element.attr('data-height-option') != 'content-adaptive') 616 return; 617 618 const item = element.parents('.block-customizer-item'); 619 element.get(0).style.setProperty('height', parseInt(element.find('.content').outerHeight() + parseInt(item.css('padding-top')) + parseInt(item.css('padding-bottom'))) + 'px', 'important'); 620 } 621} 622 623$(document).on('ready', e => { 624 $('.block-customizer').each((index, element) => { 625 new BlockCustomizer($(element)); 626 }); 627});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.