Created
September 4, 2019 19:06
-
-
Save Pross/a10148a322a5a99a8f5799fdbfd38f97 to your computer and use it in GitHub Desktop.
bb-plugin/js/fl-builder-layout.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function($){ | |
if(typeof FLBuilderLayout != 'undefined') { | |
return; | |
} | |
/** | |
* Helper class with generic logic for a builder layout. | |
* | |
* @class FLBuilderLayout | |
* @since 1.0 | |
*/ | |
FLBuilderLayout = { | |
/** | |
* Initializes a builder layout. | |
* | |
* @since 1.0 | |
* @method init | |
*/ | |
init: function() | |
{ | |
// Destroy existing layout events. | |
FLBuilderLayout._destroy(); | |
// Init CSS classes. | |
FLBuilderLayout._initClasses(); | |
// Init backgrounds. | |
FLBuilderLayout._initBackgrounds(); | |
// Only init if the builder isn't active. | |
if ( 0 === $('.fl-builder-edit').length ) { | |
// Init module animations. | |
FLBuilderLayout._initModuleAnimations(); | |
// Init anchor links. | |
FLBuilderLayout._initAnchorLinks(); | |
// Init the browser hash. | |
FLBuilderLayout._initHash(); | |
// Init forms. | |
FLBuilderLayout._initForms(); | |
} | |
}, | |
/** | |
* Public method for refreshing Wookmark or MosaicFlow galleries | |
* within an element. | |
* | |
* @since 1.7.4 | |
* @method refreshGalleries | |
*/ | |
refreshGalleries: function( element ) | |
{ | |
var $element = 'undefined' == typeof element ? $( 'body' ) : $( element ), | |
mfContent = $element.find( '.fl-mosaicflow-content' ), | |
wmContent = $element.find( '.fl-gallery' ), | |
mfObject = null; | |
if ( mfContent ) { | |
mfObject = mfContent.data( 'mosaicflow' ); | |
if ( mfObject ) { | |
mfObject.columns = $( [] ); | |
mfObject.columnsHeights = []; | |
mfContent.data( 'mosaicflow', mfObject ); | |
mfContent.mosaicflow( 'refill' ); | |
} | |
} | |
if ( wmContent ) { | |
wmContent.trigger( 'refreshWookmark' ); | |
} | |
}, | |
/** | |
* Public method for refreshing Masonry within an element | |
* | |
* @since 1.8.1 | |
* @method refreshGridLayout | |
*/ | |
refreshGridLayout: function( element ) | |
{ | |
var $element = 'undefined' == typeof element ? $( 'body' ) : $( element ), | |
msnryContent = $element.find('.masonry'); | |
if ( msnryContent.length ) { | |
msnryContent.masonry('layout'); | |
} | |
}, | |
/** | |
* Public method for reloading BxSlider within an element | |
* | |
* @since 1.8.1 | |
* @method reloadSlider | |
*/ | |
reloadSlider: function( element ) | |
{ | |
var $element = 'undefined' == typeof element ? $( 'body' ) : $( element ), | |
bxContent = $element.find('.bx-viewport > div').eq(0), | |
bxObject = null; | |
if ( bxContent.length ) { | |
bxObject = bxContent.data( 'bxSlider'); | |
if ( bxObject ) { | |
bxObject.reloadSlider(); | |
} | |
} | |
}, | |
/** | |
* Public method for resizing WP audio player | |
* | |
* @since 1.8.2 | |
* @method resizeAudio | |
*/ | |
resizeAudio: function( element ) | |
{ | |
var $element = 'undefined' == typeof element ? $( 'body' ) : $( element ), | |
audioPlayers = $element.find('.wp-audio-shortcode.mejs-audio'), | |
player = null, | |
mejsPlayer = null, | |
rail = null, | |
railWidth = 400; | |
if ( audioPlayers.length && typeof mejs !== 'undefined' ) { | |
audioPlayers.each(function(){ | |
player = $(this); | |
mejsPlayer = mejs.players[player.attr('id')]; | |
rail = player.find('.mejs-controls .mejs-time-rail'); | |
var innerMejs = player.find('.mejs-inner'), | |
total = player.find('.mejs-controls .mejs-time-total'); | |
if ( typeof mejsPlayer !== 'undefined' ) { | |
railWidth = Math.ceil(player.width() * 0.8); | |
if ( innerMejs.length ) { | |
rail.css('width', railWidth +'px!important'); | |
//total.width(rail.width() - 10); | |
mejsPlayer.options.autosizeProgress = true; | |
// webkit has trouble doing this without a delay | |
setTimeout(function () { | |
mejsPlayer.setControlsSize(); | |
}, 50); | |
player.find('.mejs-inner').css({ | |
visibility: 'visible', | |
height: 'inherit' | |
}); | |
} | |
} | |
}); | |
} | |
}, | |
/** | |
* Public method for preloading WP audio player when it's inside the hidden element | |
* | |
* @since 1.8.2 | |
* @method preloadAudio | |
*/ | |
preloadAudio: function(element) | |
{ | |
var $element = 'undefined' == typeof element ? $( 'body' ) : $( element ), | |
contentWrap = $element.closest('.fl-accordion-item'), | |
audioPlayers = $element.find('.wp-audio-shortcode.mejs-audio'); | |
if ( ! contentWrap.hasClass('fl-accordion-item-active') && audioPlayers.find('.mejs-inner').length ) { | |
audioPlayers.find('.mejs-inner').css({ | |
visibility : 'hidden', | |
height: 0 | |
}); | |
} | |
}, | |
/** | |
* Public method for resizing slideshow momdule within the tab | |
* | |
* @since 1.10.5 | |
* @method resizeSlideshow | |
*/ | |
resizeSlideshow: function(){ | |
if(typeof YUI !== 'undefined') { | |
YUI().use('node-event-simulate', function(Y) { | |
Y.one(window).simulate("resize"); | |
}); | |
} | |
}, | |
/** | |
* Public method for reloading an embedded Google Map within the tabs or hidden element. | |
* | |
* @since 2.2 | |
* @method reloadGoogleMap | |
*/ | |
reloadGoogleMap: function(element){ | |
var $element = 'undefined' == typeof element ? $( 'body' ) : $( element ), | |
googleMap = $element.find( 'iframe[src*="google.com/maps"]' ); | |
if ( googleMap.length ) { | |
googleMap.attr( 'src', function(i, val) { | |
return val; | |
}); | |
} | |
}, | |
/** | |
* Unbinds builder layout events. | |
* | |
* @since 1.0 | |
* @access private | |
* @method _destroy | |
*/ | |
_destroy: function() | |
{ | |
var win = $(window); | |
win.off('scroll.fl-bg-parallax'); | |
win.off('resize.fl-bg-video'); | |
}, | |
/** | |
* Checks to see if the current device has touch enabled. | |
* | |
* @since 1.0 | |
* @access private | |
* @method _isTouch | |
* @return {Boolean} | |
*/ | |
_isTouch: function() | |
{ | |
if(('ontouchstart' in window) || (window.DocumentTouch && document instanceof DocumentTouch)) { | |
return true; | |
} | |
return false; | |
}, | |
/** | |
* Checks to see if the current device is mobile. | |
* | |
* @since 1.7 | |
* @access private | |
* @method _isMobile | |
* @return {Boolean} | |
*/ | |
_isMobile: function() | |
{ | |
return /Mobile|Android|Silk\/|Kindle|BlackBerry|Opera Mini|Opera Mobi|webOS/i.test( navigator.userAgent ); | |
}, | |
/** | |
* Initializes builder body classes. | |
* | |
* @since 1.0 | |
* @access private | |
* @method _initClasses | |
*/ | |
_initClasses: function() | |
{ | |
var body = $( 'body' ), | |
ua = navigator.userAgent; | |
// Add the builder body class. | |
if ( ! body.hasClass( 'archive' ) && $( '.fl-builder-content-primary' ).length > 0 ) { | |
body.addClass('fl-builder'); | |
} | |
// Add the builder touch body class. | |
if(FLBuilderLayout._isTouch()) { | |
body.addClass('fl-builder-touch'); | |
} | |
// Add the builder mobile body class. | |
if(FLBuilderLayout._isMobile()) { | |
body.addClass('fl-builder-mobile'); | |
} | |
// IE11 body class. | |
if ( ua.indexOf( 'Trident/7.0' ) > -1 && ua.indexOf( 'rv:11.0' ) > -1 ) { | |
body.addClass( 'fl-builder-ie-11' ); | |
} | |
}, | |
/** | |
* Initializes builder node backgrounds that require | |
* additional JavaScript logic such as parallax. | |
* | |
* @since 1.1.4 | |
* @access private | |
* @method _initBackgrounds | |
*/ | |
_initBackgrounds: function() | |
{ | |
var win = $(window); | |
// Init parallax backgrounds. | |
if($('.fl-row-bg-parallax').length > 0 && !FLBuilderLayout._isMobile()) { | |
FLBuilderLayout._scrollParallaxBackgrounds(); | |
FLBuilderLayout._initParallaxBackgrounds(); | |
win.on('scroll.fl-bg-parallax', FLBuilderLayout._scrollParallaxBackgrounds); | |
} | |
// Init video backgrounds. | |
if($('.fl-bg-video').length > 0) { | |
FLBuilderLayout._initBgVideos(); | |
FLBuilderLayout._resizeBgVideos(); | |
win.on('resize.fl-bg-video', FLBuilderLayout._resizeBgVideos); | |
} | |
}, | |
/** | |
* Initializes all parallax backgrounds in a layout. | |
* | |
* @since 1.1.4 | |
* @access private | |
* @method _initParallaxBackgrounds | |
*/ | |
_initParallaxBackgrounds: function() | |
{ | |
$('.fl-row-bg-parallax').each(FLBuilderLayout._initParallaxBackground); | |
}, | |
/** | |
* Initializes a single parallax background. | |
* | |
* @since 1.1.4 | |
* @access private | |
* @method _initParallaxBackgrounds | |
*/ | |
_initParallaxBackground: function() | |
{ | |
var row = $(this), | |
content = row.find('> .fl-row-content-wrap'), | |
src = row.data('parallax-image'), | |
loaded = row.data('parallax-loaded'), | |
img = new Image(); | |
if(loaded) { | |
return; | |
} | |
else if(typeof src != 'undefined') { | |
$(img).on('load', function() { | |
content.css('background-image', 'url(' + src + ')'); | |
row.data('parallax-loaded', true); | |
}); | |
img.src = src; | |
} | |
}, | |
/** | |
* Fires when the window is scrolled to adjust | |
* parallax backgrounds. | |
* | |
* @since 1.1.4 | |
* @access private | |
* @method _scrollParallaxBackgrounds | |
*/ | |
_scrollParallaxBackgrounds: function() | |
{ | |
$('.fl-row-bg-parallax').each(FLBuilderLayout._scrollParallaxBackground); | |
}, | |
/** | |
* Fires when the window is scrolled to adjust | |
* a single parallax background. | |
* | |
* @since 1.1.4 | |
* @access private | |
* @method _scrollParallaxBackground | |
*/ | |
_scrollParallaxBackground: function() | |
{ | |
var win = $(window), | |
row = $(this), | |
content = row.find('> .fl-row-content-wrap'), | |
speed = row.data('parallax-speed'), | |
offset = content.offset(), | |
yPos = -((win.scrollTop() - offset.top) / speed); | |
content.css('background-position', 'center ' + yPos + 'px'); | |
}, | |
/** | |
* Initializes all video backgrounds. | |
* | |
* @since 1.6.3.3 | |
* @access private | |
* @method _initBgVideos | |
*/ | |
_initBgVideos: function() | |
{ | |
$('.fl-bg-video').each(FLBuilderLayout._initBgVideo); | |
}, | |
/** | |
* Initializes a video background. | |
* | |
* @since 1.6.3.3 | |
* @access private | |
* @method _initBgVideo | |
*/ | |
_initBgVideo: function() | |
{ | |
var wrap = $( this ), | |
width = wrap.data( 'width' ), | |
height = wrap.data( 'height' ), | |
mp4 = wrap.data( 'mp4' ), | |
youtube = wrap.data( 'youtube'), | |
vimeo = wrap.data( 'vimeo'), | |
mp4Type = wrap.data( 'mp4-type' ), | |
webm = wrap.data( 'webm' ), | |
webmType = wrap.data( 'webm-type' ), | |
fallback = wrap.data( 'fallback' ), | |
loaded = wrap.data( 'loaded' ), | |
videoMobile = wrap.data( 'video-mobile' ), | |
fallbackTag = '', | |
videoTag = null, | |
mp4Tag = null, | |
webmTag = null; | |
// Return if the video has been loaded for this row. | |
if ( loaded ) { | |
return; | |
} | |
videoTag = $( '<video autoplay loop muted playsinline></video>' ); | |
/** | |
* Add poster image (fallback image) | |
*/ | |
if( 'undefined' != typeof fallback && '' != fallback ) { | |
videoTag.attr( 'poster', 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' ) | |
videoTag.css( 'background', 'transparent url("' + fallback + '") no-repeat center center' ) | |
videoTag.css( 'background-size', 'cover' ) | |
videoTag.css( 'height', '100%' ) | |
} | |
// MP4 Source Tag | |
if ( 'undefined' != typeof mp4 && '' != mp4 ) { | |
mp4Tag = $( '<source />' ); | |
mp4Tag.attr( 'src', mp4 ); | |
mp4Tag.attr( 'type', mp4Type ); | |
videoTag.append( mp4Tag ); | |
} | |
// WebM Source Tag | |
if ( 'undefined' != typeof webm && '' != webm ) { | |
webmTag = $( '<source />' ); | |
webmTag.attr( 'src', webm ); | |
webmTag.attr( 'type', webmType ); | |
videoTag.append( webmTag ); | |
} | |
// Check what video player we are going to load in a row | |
if ( ! FLBuilderLayout._isMobile() || ( FLBuilderLayout._isMobile() && "yes" == videoMobile ) ) { | |
if ( 'undefined' != typeof youtube ) { | |
FLBuilderLayout._initYoutubeBgVideo.apply( this ); | |
} | |
else if ( 'undefined' != typeof vimeo ) { | |
FLBuilderLayout._initVimeoBgVideo.apply( this ); | |
} | |
else { | |
wrap.append( videoTag ); | |
} | |
} | |
// Mark this video as loaded. | |
wrap.data('loaded', true); | |
}, | |
/** | |
* Initializes Youtube video background | |
* | |
* @since 1.9 | |
* @access private | |
* @method _initYoutubeBgVideo | |
*/ | |
_initYoutubeBgVideo: function() | |
{ | |
var playerWrap = $(this), | |
videoId = playerWrap.data('video-id'), | |
videoPlayer = playerWrap.find('.fl-bg-video-player'), | |
enableAudio = playerWrap.data('enable-audio'), | |
audioButton = playerWrap.find('.fl-bg-video-audio'), | |
startTime = 'undefined' !== typeof playerWrap.data('start') ? playerWrap.data('start') : 0, | |
endTime = 'undefined' !== typeof playerWrap.data('end') ? playerWrap.data('end') : 0, | |
loop = 'undefined' !== typeof playerWrap.data('loop') ? playerWrap.data('loop') : 1, | |
stateCount = 0, | |
player; | |
if ( videoId ) { | |
FLBuilderLayout._onYoutubeApiReady( function( YT ) { | |
setTimeout( function() { | |
player = new YT.Player( videoPlayer[0], { | |
videoId: videoId, | |
events: { | |
onReady: function(event) { | |
if ( "no" === enableAudio || FLBuilderLayout._isMobile() ) { | |
event.target.mute(); | |
} | |
else if ( "yes" === enableAudio && event.target.isMuted ) { | |
event.target.unMute(); | |
} | |
// Store an instance to a parent | |
playerWrap.data('YTPlayer', player); | |
FLBuilderLayout._resizeYoutubeBgVideo.apply(playerWrap); | |
// Queue the video. | |
event.target.playVideo(); | |
if ( audioButton.length > 0 && ! FLBuilderLayout._isMobile() ) { | |
audioButton.on( 'click', {button: audioButton, player: player}, FLBuilderLayout._toggleBgVideoAudio ); | |
} | |
}, | |
onStateChange: function( event ) { | |
// Manual check if video is not playable in some browsers. | |
// StateChange order: [-1, 3, -1] | |
if ( stateCount < 4 ) { | |
stateCount++; | |
} | |
// Comply with the audio policy in some browsers like Chrome and Safari. | |
if ( stateCount > 1 && (-1 === event.data || 2 === event.data) && "yes" === enableAudio ) { | |
player.mute(); | |
player.playVideo(); | |
audioButton.show(); | |
} | |
if ( event.data === YT.PlayerState.ENDED && 1 === loop ) { | |
if ( startTime > 0 ) { | |
player.seekTo( startTime ); | |
} | |
else { | |
player.playVideo(); | |
} | |
} | |
}, | |
onError: function(event) { | |
console.info('YT Error: ' + event.data) | |
FLBuilderLayout._onErrorYoutubeVimeo(playerWrap) | |
} | |
}, | |
playerVars: { | |
playsinline: FLBuilderLayout._isMobile() ? 1 : 0, | |
controls: 0, | |
showinfo: 0, | |
rel : 0, | |
start: startTime, | |
end: endTime, | |
} | |
} ); | |
}, 1 ); | |
} ); | |
} | |
}, | |
/** | |
* On youtube or vimeo error show the fallback image if available. | |
* @since 2.0.7 | |
*/ | |
_onErrorYoutubeVimeo: function(playerWrap) { | |
fallback = playerWrap.data('fallback') || false | |
if( ! fallback ) { | |
return false; | |
} | |
playerWrap.find('iframe').remove() | |
fallbackTag = $( '<div></div>' ); | |
fallbackTag.addClass( 'fl-bg-video-fallback' ); | |
fallbackTag.css( 'background-image', 'url(' + playerWrap.data('fallback') + ')' ); | |
playerWrap.append( fallbackTag ); | |
}, | |
/** | |
* Check if Youtube API has been downloaded | |
* | |
* @since 1.9 | |
* @access private | |
* @method _onYoutubeApiReady | |
* @param {Function} callback Method to call when YT API has been loaded | |
*/ | |
_onYoutubeApiReady: function( callback ) { | |
if ( window.YT && YT.loaded ) { | |
callback( YT ); | |
} else { | |
// If not ready check again by timeout.. | |
setTimeout( function() { | |
FLBuilderLayout._onYoutubeApiReady( callback ); | |
}, 350 ); | |
} | |
}, | |
/** | |
* Initializes Vimeo video background | |
* | |
* @since 1.9 | |
* @access private | |
* @method _initVimeoBgVideo | |
*/ | |
_initVimeoBgVideo: function() | |
{ | |
var playerWrap = $(this), | |
videoId = playerWrap.data('video-id'), | |
videoPlayer = playerWrap.find('.fl-bg-video-player'), | |
enableAudio = playerWrap.data('enable-audio'), | |
audioButton = playerWrap.find('.fl-bg-video-audio'), | |
player, | |
width = playerWrap.outerWidth(); | |
if ( typeof Vimeo !== 'undefined' && videoId ) { | |
player = new Vimeo.Player(videoPlayer[0], { | |
id : videoId, | |
loop : true, | |
title : false, | |
portrait : false, | |
background : true, | |
autopause : false, | |
muted : true | |
}); | |
playerWrap.data('VMPlayer', player); | |
if ( "no" === enableAudio ) { | |
player.setVolume(0); | |
} | |
else if ("yes" === enableAudio ) { | |
// Chrome and Safari have audio policy restrictions for autoplay videos. | |
if ( $.browser.safari || $.browser.chrome ) { | |
player.setVolume(0); | |
audioButton.show(); | |
} | |
else { | |
player.setVolume(1); | |
} | |
} | |
player.play().catch(function(error) { | |
FLBuilderLayout._onErrorYoutubeVimeo(playerWrap) | |
}); | |
if ( audioButton.length > 0 ) { | |
audioButton.on( 'click', {button: audioButton, player: player}, FLBuilderLayout._toggleBgVideoAudio ); | |
} | |
} | |
}, | |
/** | |
* Mute / unmute audio on row's video background. | |
* It works for both Youtube and Vimeo. | |
* | |
* @since 2.1.3 | |
* @access private | |
* @method _toggleBgVideoAudio | |
* @param {Object} e Method arguments | |
*/ | |
_toggleBgVideoAudio: function( e ) { | |
var player = e.data.player, | |
control = e.data.button.find('.fl-audio-control'); | |
if ( control.hasClass( 'fa-volume-off' ) ) { | |
// Unmute | |
control | |
.removeClass( 'fa-volume-off' ) | |
.addClass( 'fa-volume-up' ); | |
e.data.button.find( '.fa-times' ).hide(); | |
if ( 'function' === typeof player.unMute ) { | |
player.unMute(); | |
} | |
else { | |
player.setVolume( 1 ); | |
} | |
} | |
else { | |
// Mute | |
control | |
.removeClass( 'fa-volume-up' ) | |
.addClass( 'fa-volume-off' ); | |
e.data.button.find( '.fa-times' ).show(); | |
if ( 'function' === typeof player.unMute ) { | |
player.mute(); | |
} | |
else { | |
player.setVolume( 0 ); | |
} | |
} | |
}, | |
/** | |
* Fires when there is an error loading a video | |
* background source and shows the fallback. | |
* | |
* @since 1.6.3.3 | |
* @access private | |
* @method _videoBgSourceError | |
* @param {Object} e An event object | |
* @deprecated 2.0.3 | |
*/ | |
_videoBgSourceError: function( e ) | |
{ | |
var source = $( e.target ), | |
wrap = source.closest( '.fl-bg-video' ), | |
vid = wrap.find( 'video' ), | |
fallback = wrap.data( 'fallback' ), | |
fallbackTag = ''; | |
source.remove(); | |
if ( vid.find( 'source' ).length ) { | |
// Don't show the fallback if we still have other sources to check. | |
return; | |
} else if ( '' !== fallback ) { | |
fallbackTag = $( '<div></div>' ); | |
fallbackTag.addClass( 'fl-bg-video-fallback' ); | |
fallbackTag.css( 'background-image', 'url(' + fallback + ')' ); | |
wrap.append( fallbackTag ); | |
vid.remove(); | |
} | |
}, | |
/** | |
* Fires when the window is resized to resize | |
* all video backgrounds. | |
* | |
* @since 1.1.4 | |
* @access private | |
* @method _resizeBgVideos | |
*/ | |
_resizeBgVideos: function() | |
{ | |
$('.fl-bg-video').each( function() { | |
FLBuilderLayout._resizeBgVideo.apply( this ); | |
if ( $( this ).parent().find( 'img' ).length > 0 ) { | |
$( this ).parent().imagesLoaded( $.proxy( FLBuilderLayout._resizeBgVideo, this ) ); | |
} | |
} ); | |
}, | |
/** | |
* Fires when the window is resized to resize | |
* a single video background. | |
* | |
* @since 1.1.4 | |
* @access private | |
* @method _resizeBgVideo | |
*/ | |
_resizeBgVideo: function() | |
{ | |
if ( 0 === $( this ).find( 'video' ).length && 0 === $( this ).find( 'iframe' ).length ) { | |
return; | |
} | |
var wrap = $(this), | |
wrapHeight = wrap.outerHeight(), | |
wrapWidth = wrap.outerWidth(), | |
vid = wrap.find('video'), | |
vidHeight = wrap.data('height'), | |
vidWidth = wrap.data('width'), | |
newWidth = wrapWidth, | |
newHeight = Math.round(vidHeight * wrapWidth/vidWidth), | |
newLeft = 0, | |
newTop = 0, | |
iframe = wrap.find('iframe'); | |
if ( vid.length ) { | |
if(vidHeight === '' || typeof vidHeight === 'undefined' || vidWidth === '' || typeof vidWidth === 'undefined') { | |
vid.css({ | |
'left' : '0px', | |
'top' : '0px', | |
'width' : newWidth + 'px' | |
}); | |
// Try to set the actual video dimension on 'loadedmetadata' when using URL as video source | |
vid.on('loadedmetadata', FLBuilderLayout._resizeOnLoadedMeta); | |
} | |
else { | |
if(newHeight < wrapHeight) { | |
newHeight = wrapHeight; | |
newWidth = Math.round(vidWidth * wrapHeight/vidHeight); | |
newLeft = -((newWidth - wrapWidth)/2); | |
} | |
else { | |
newTop = -((newHeight - wrapHeight)/2); | |
} | |
vid.css({ | |
'left' : newLeft + 'px', | |
'top' : newTop + 'px', | |
'height' : newHeight + 'px', | |
'width' : newWidth + 'px' | |
}); | |
} | |
} | |
else if ( iframe.length ) { | |
// Resize Youtube video player within iframe tag | |
if ( typeof wrap.data('youtube') !== 'undefined' ) { | |
FLBuilderLayout._resizeYoutubeBgVideo.apply(this); | |
} | |
} | |
}, | |
/** | |
* Fires when video meta has been loaded. | |
* This will be Triggered when width/height attributes were not specified during video background resizing. | |
* | |
* @since 1.8.5 | |
* @access private | |
* @method _resizeOnLoadedMeta | |
*/ | |
_resizeOnLoadedMeta: function(){ | |
var video = $(this), | |
wrapHeight = video.parent().outerHeight(), | |
wrapWidth = video.parent().outerWidth(), | |
vidWidth = video[0].videoWidth, | |
vidHeight = video[0].videoHeight, | |
newHeight = Math.round(vidHeight * wrapWidth/vidWidth), | |
newWidth = wrapWidth, | |
newLeft = 0, | |
newTop = 0; | |
if(newHeight < wrapHeight) { | |
newHeight = wrapHeight; | |
newWidth = Math.round(vidWidth * wrapHeight/vidHeight); | |
newLeft = -((newWidth - wrapWidth)/2); | |
} | |
else { | |
newTop = -((newHeight - wrapHeight)/2); | |
} | |
video.parent().data('width', vidWidth); | |
video.parent().data('height', vidHeight); | |
video.css({ | |
'left' : newLeft + 'px', | |
'top' : newTop + 'px', | |
'width' : newWidth + 'px', | |
'height' : newHeight + 'px' | |
}); | |
}, | |
/** | |
* Fires when the window is resized to resize | |
* a single Youtube video background. | |
* | |
* @since 1.9 | |
* @access private | |
* @method _resizeYoutubeBgVideo | |
*/ | |
_resizeYoutubeBgVideo: function() | |
{ | |
var wrap = $(this), | |
wrapWidth = wrap.outerWidth(), | |
wrapHeight = wrap.outerHeight(), | |
player = wrap.data('YTPlayer'), | |
video = player ? player.getIframe() : null, | |
aspectRatioSetting = '16:9', // Medium | |
aspectRatioArray = aspectRatioSetting.split( ':' ), | |
aspectRatio = aspectRatioArray[0] / aspectRatioArray[1], | |
ratioWidth = wrapWidth / aspectRatio, | |
ratioHeight = wrapHeight * aspectRatio, | |
isWidthFixed = wrapWidth / wrapHeight > aspectRatio, | |
width = isWidthFixed ? wrapWidth : ratioHeight, | |
height = isWidthFixed ? ratioWidth : wrapHeight; | |
if ( video ) { | |
$(video).width( width ).height( height ); | |
} | |
}, | |
/** | |
* Initializes module animations. | |
* | |
* @since 1.1.9 | |
* @access private | |
* @method _initModuleAnimations | |
*/ | |
_initModuleAnimations: function() | |
{ | |
if(typeof jQuery.fn.waypoint !== 'undefined') { | |
$('.fl-animation').each( function() { | |
var node = $( this ), | |
nodeTop = node.offset().top, | |
winHeight = $( window ).height(), | |
bodyHeight = $( 'body' ).height(), | |
waypoint = FLBuilderLayoutConfig.waypoint, | |
offset = '80%'; | |
if ( typeof waypoint.offset !== undefined ) { | |
offset = FLBuilderLayoutConfig.waypoint.offset + '%'; | |
} | |
if ( bodyHeight - nodeTop < winHeight * 0.2 ) { | |
offset = '100%'; | |
} | |
node.waypoint({ | |
offset: offset, | |
handler: FLBuilderLayout._doModuleAnimation | |
}); | |
} ); | |
} | |
}, | |
/** | |
* Runs a module animation. | |
* | |
* @since 1.1.9 | |
* @access private | |
* @method _doModuleAnimation | |
*/ | |
_doModuleAnimation: function() | |
{ | |
var module = 'undefined' == typeof this.element ? $(this) : $(this.element), | |
delay = parseFloat(module.data('animation-delay')), | |
duration = parseFloat(module.data('animation-duration')); | |
if ( ! isNaN( duration ) ) { | |
module.css( 'animation-duration', duration + 's' ); | |
} | |
if(!isNaN(delay) && delay > 0) { | |
setTimeout(function(){ | |
module.addClass('fl-animated'); | |
}, delay * 1000); | |
} else { | |
setTimeout(function(){ | |
module.addClass('fl-animated'); | |
}, 1); | |
} | |
}, | |
/** | |
* Opens a tab or accordion item if the browser hash is set | |
* to the ID of one on the page. | |
* | |
* @since 1.6.0 | |
* @access private | |
* @method _initHash | |
*/ | |
_initHash: function() | |
{ | |
var hash = window.location.hash.replace( '#', '' ).split( '/' ).shift(), | |
element = null, | |
tabs = null, | |
responsiveLabel = null, | |
tabIndex = null, | |
label = null; | |
if ( '' !== hash ) { | |
try { | |
element = $( '#' + hash ); | |
if ( element.length > 0 ) { | |
if ( element.hasClass( 'fl-accordion-item' ) ) { | |
setTimeout( function() { | |
element.find( '.fl-accordion-button' ).trigger( 'click' ); | |
}, 100 ); | |
} | |
if ( element.hasClass( 'fl-tabs-panel' ) ) { | |
setTimeout( function() { | |
tabs = element.closest( '.fl-tabs' ); | |
responsiveLabel = element.find( '.fl-tabs-panel-label' ); | |
tabIndex = responsiveLabel.data( 'index' ); | |
label = tabs.find( '.fl-tabs-labels .fl-tabs-label[data-index=' + tabIndex + ']' ); | |
if ( responsiveLabel.is( ':visible' ) ) { | |
responsiveLabel.trigger( 'click' ); | |
} | |
else { | |
label[0].click(); | |
FLBuilderLayout._scrollToElement( element ); | |
} | |
}, 100 ); | |
} | |
} | |
} | |
catch( e ) {} | |
} | |
}, | |
/** | |
* Initializes all anchor links on the page for smooth scrolling. | |
* | |
* @since 1.4.9 | |
* @access private | |
* @method _initAnchorLinks | |
*/ | |
_initAnchorLinks: function() | |
{ | |
$( 'a' ).each( FLBuilderLayout._initAnchorLink ); | |
}, | |
/** | |
* Initializes a single anchor link for smooth scrolling. | |
* | |
* @since 1.4.9 | |
* @access private | |
* @method _initAnchorLink | |
*/ | |
_initAnchorLink: function() | |
{ | |
var link = $( this ), | |
href = link.attr( 'href' ), | |
loc = window.location, | |
id = null, | |
element = null; | |
if ( 'undefined' != typeof href && href.indexOf( '#' ) > -1 && link.closest('svg').length < 1 ) { | |
if ( loc.pathname.replace( /^\//, '' ) == this.pathname.replace( /^\//, '' ) && loc.hostname == this.hostname ) { | |
try { | |
id = href.split( '#' ).pop(); | |
// If there is no ID then we have nowhere to look | |
// Fixes a quirk in jQuery and FireFox | |
if( ! id ) { | |
return; | |
} | |
element = $( '#' + id ); | |
if ( element.length > 0 ) { | |
if ( link.hasClass( 'fl-scroll-link' ) || element.hasClass( 'fl-row' ) || element.hasClass( 'fl-col' ) || element.hasClass( 'fl-module' ) ) { | |
$( link ).on( 'click', FLBuilderLayout._scrollToElementOnLinkClick ); | |
} | |
if ( element.hasClass( 'fl-accordion-item' ) ) { | |
$( link ).on( 'click', FLBuilderLayout._scrollToAccordionOnLinkClick ); | |
} | |
if ( element.hasClass( 'fl-tabs-panel' ) ) { | |
$( link ).on( 'click', FLBuilderLayout._scrollToTabOnLinkClick ); | |
} | |
} | |
} | |
catch( e ) {} | |
} | |
} | |
}, | |
/** | |
* Scrolls to an element when an anchor link is clicked. | |
* | |
* @since 1.4.9 | |
* @access private | |
* @method _scrollToElementOnLinkClick | |
* @param {Object} e An event object. | |
* @param {Function} callback A function to call when the scroll is complete. | |
*/ | |
_scrollToElementOnLinkClick: function( e, callback ) | |
{ | |
var element = $( '#' + $( this ).attr( 'href' ).split( '#' ).pop() ); | |
FLBuilderLayout._scrollToElement( element, callback ); | |
e.preventDefault(); | |
}, | |
/** | |
* Scrolls to an element. | |
* | |
* @since 1.6.4.5 | |
* @access private | |
* @method _scrollToElement | |
* @param {Object} element The element to scroll to. | |
* @param {Function} callback A function to call when the scroll is complete. | |
*/ | |
_scrollToElement: function( element, callback ) | |
{ | |
var config = FLBuilderLayoutConfig.anchorLinkAnimations, | |
dest = 0, | |
win = $( window ), | |
doc = $( document ); | |
if ( element.length > 0 ) { | |
if ( element.offset().top > doc.height() - win.height() ) { | |
dest = doc.height() - win.height(); | |
} | |
else { | |
dest = element.offset().top - config.offset; | |
} | |
$( 'html, body' ).animate( { scrollTop: dest }, config.duration, config.easing, function() { | |
if ( 'undefined' != typeof callback ) { | |
callback(); | |
} | |
if ( undefined != element.attr( 'id' ) ) { | |
if ( history.pushState ) { | |
history.pushState( null, null, '#' + element.attr( 'id' ) ); | |
} | |
else { | |
window.location.hash = element.attr( 'id' ); | |
} | |
} | |
} ); | |
} | |
}, | |
/** | |
* Scrolls to an accordion item when a link is clicked. | |
* | |
* @since 1.5.9 | |
* @access private | |
* @method _scrollToAccordionOnLinkClick | |
* @param {Object} e An event object. | |
*/ | |
_scrollToAccordionOnLinkClick: function( e ) | |
{ | |
var element = $( '#' + $( this ).attr( 'href' ).split( '#' ).pop() ); | |
if ( element.length > 0 ) { | |
var callback = function() { | |
if ( element ) { | |
element.find( '.fl-accordion-button' ).trigger( 'click' ); | |
element = false; | |
} | |
}; | |
FLBuilderLayout._scrollToElementOnLinkClick.call( this, e, callback ); | |
} | |
}, | |
/** | |
* Scrolls to a tab panel when a link is clicked. | |
* | |
* @since 1.5.9 | |
* @access private | |
* @method _scrollToTabOnLinkClick | |
* @param {Object} e An event object. | |
*/ | |
_scrollToTabOnLinkClick: function( e ) | |
{ | |
var element = $( '#' + $( this ).attr( 'href' ).split( '#' ).pop() ), | |
tabs = null, | |
label = null, | |
responsiveLabel = null; | |
if ( element.length > 0 ) { | |
tabs = element.closest( '.fl-tabs' ); | |
responsiveLabel = element.find( '.fl-tabs-panel-label' ); | |
tabIndex = responsiveLabel.data( 'index' ); | |
label = tabs.find( '.fl-tabs-labels .fl-tabs-label[data-index=' + tabIndex + ']' ); | |
if ( responsiveLabel.is( ':visible' ) ) { | |
var callback = function() { | |
if ( element ) { | |
responsiveLabel.trigger( 'click' ); | |
element = false; | |
} | |
}; | |
FLBuilderLayout._scrollToElementOnLinkClick.call( this, e, callback ); | |
} | |
else { | |
label[0].click(); | |
FLBuilderLayout._scrollToElement( element ); | |
} | |
e.preventDefault(); | |
} | |
}, | |
/** | |
* Initializes all builder forms on a page. | |
* | |
* @since 1.5.4 | |
* @access private | |
* @method _initForms | |
*/ | |
_initForms: function() | |
{ | |
if ( ! FLBuilderLayout._hasPlaceholderSupport ) { | |
$( '.fl-form-field input' ).each( FLBuilderLayout._initFormFieldPlaceholderFallback ); | |
} | |
$( '.fl-form-field input' ).on( 'focus', FLBuilderLayout._clearFormFieldError ); | |
}, | |
/** | |
* Checks to see if the current device has HTML5 | |
* placeholder support. | |
* | |
* @since 1.5.4 | |
* @access private | |
* @method _hasPlaceholderSupport | |
* @return {Boolean} | |
*/ | |
_hasPlaceholderSupport: function() | |
{ | |
var input = document.createElement( 'input' ); | |
return 'undefined' != input.placeholder; | |
}, | |
/** | |
* Initializes the fallback for when placeholders aren't supported. | |
* | |
* @since 1.5.4 | |
* @access private | |
* @method _initFormFieldPlaceholderFallback | |
*/ | |
_initFormFieldPlaceholderFallback: function() | |
{ | |
var field = $( this ), | |
val = field.val(), | |
placeholder = field.attr( 'placeholder' ); | |
if ( 'undefined' != placeholder && '' === val ) { | |
field.val( placeholder ); | |
field.on( 'focus', FLBuilderLayout._hideFormFieldPlaceholderFallback ); | |
field.on( 'blur', FLBuilderLayout._showFormFieldPlaceholderFallback ); | |
} | |
}, | |
/** | |
* Hides a fallback placeholder on focus. | |
* | |
* @since 1.5.4 | |
* @access private | |
* @method _hideFormFieldPlaceholderFallback | |
*/ | |
_hideFormFieldPlaceholderFallback: function() | |
{ | |
var field = $( this ), | |
val = field.val(), | |
placeholder = field.attr( 'placeholder' ); | |
if ( val == placeholder ) { | |
field.val( '' ); | |
} | |
}, | |
/** | |
* Shows a fallback placeholder on blur. | |
* | |
* @since 1.5.4 | |
* @access private | |
* @method _showFormFieldPlaceholderFallback | |
*/ | |
_showFormFieldPlaceholderFallback: function() | |
{ | |
var field = $( this ), | |
val = field.val(), | |
placeholder = field.attr( 'placeholder' ); | |
if ( '' === val ) { | |
field.val( placeholder ); | |
} | |
}, | |
/** | |
* Clears a form field error message. | |
* | |
* @since 1.5.4 | |
* @access private | |
* @method _clearFormFieldError | |
*/ | |
_clearFormFieldError: function() | |
{ | |
var field = $( this ); | |
field.removeClass( 'fl-form-error' ); | |
field.siblings( '.fl-form-error-message' ).hide(); | |
} | |
}; | |
/* Initializes the builder layout. */ | |
$(function(){ | |
FLBuilderLayout.init(); | |
}); | |
})(jQuery); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment