(function($){
/**
* Helper class for dealing with live previews.
*
* @class FLBuilderPreview
* @since 1.3.3
* @param {Object} config
*/
FLBuilderPreview = function( config )
{
// Set the preview ID.
this.id = new Date().getTime();
// Set the type.
this.type = config.type;
// Save the current state.
this._saveState();
// Initialize the preview.
if ( config.layout ) {
FLBuilder._renderLayout( config.layout, function() {
this._init();
if ( config.callback ) {
config.callback();
}
}.bind( this ) );
} else {
this._init();
}
};
/**
* Stores all the fonts and weights of all font fields.
* This is used to render the stylesheet with Google Fonts.
*
* @since 1.6.3
* @access private
* @property {Array} _fontsList
*/
FLBuilderPreview._fontsList = {};
/**
* Returns a formatted selector string for a preview.
*
* @since 2.1
* @method getFormattedSelector
* @param {String} selector A CSS selector string.
* @return {String}
*/
FLBuilderPreview.getFormattedSelector = function( prefix, selector )
{
var formatted = '',
parts = selector.split( ',' ),
i = 0;
for ( ; i < parts.length; i++ ) {
if ( parts[ i ].indexOf( '{node}' ) > -1 ) {
formatted += parts[ i ].replace( '{node}', prefix );
} else if ( parts[ i ].indexOf( '{node_id}' ) > -1 ) {
formatted += parts[ i ].replace( /{node_id}/g, this.nodeId );
} else {
formatted += prefix + ' ' + parts[ i ];
}
if ( i != parts.length - 1 ) {
formatted += ', ';
}
}
return formatted;
};
/**
* Prototype for new instances.
*
* @since 1.3.3
* @property {Object} prototype
*/
FLBuilderPreview.prototype = {
/**
* A unique ID for this preview.
*
* @since 1.3.3
* @property {String} id
*/
id : '',
/**
* The type of node that we are previewing.
*
* @since 1.3.3
* @property {String} type
*/
type : '',
/**
* The ID of node that we are previewing.
*
* @since 1.3.3
* @property {String} nodeId
*/
nodeId : null,
/**
* An object with data for each CSS class
* in the preview.
*
* @since 1.3.3
* @property {Object} classes
*/
classes : {},
/**
* An object with references to each element
* in the preview.
*
* @since 1.3.3
* @property {Object} elements
*/
elements : {},
/**
* An object that contains data for the current
* state of a layout before changes are made.
*
* @since 1.3.3
* @property {Object} state
*/
state : null,
/**
* Node settings saved when the preview was initalized.
*
* @since 1.7
* @access private
* @property {Object} _savedSettings
*/
_savedSettings : null,
/**
* An instance of FLStyleSheet for the current preview.
*
* @since 1.3.3
* @access private
* @property {FLStyleSheet} _styleSheet
*/
_styleSheet : null,
/**
* An instance of FLStyleSheet for the large device preview.
*
* @since 2.6
* @access private
* @property {FLStyleSheet} _styleSheetLarge
*/
_styleSheetLarge : null,
/**
* An instance of FLStyleSheet for the medium device preview.
*
* @since 1.9
* @access private
* @property {FLStyleSheet} _styleSheetMedium
*/
_styleSheetMedium : null,
/**
* An instance of FLStyleSheet for the responsive device preview.
*
* @since 1.9
* @access private
* @property {FLStyleSheet} _styleSheet
*/
_styleSheetResponsive : null,
/**
* A timeout object for delaying the current preview refresh.
*
* @since 1.3.3
* @access private
* @property {Object} _timeout
*/
_timeout : null,
/**
* A timeout object for delaying when we show the loading
* graphic for refresh previews.
*
* @since 1.10
* @access private
* @property {Object} _loaderTimeout
*/
_loaderTimeout : null,
/**
* Stores the last classname for a classname preview.
*
* @since 1.3.3
* @access private
* @property {String} _lastClassName
*/
_lastClassName : null,
/**
* A reference to the AJAX object for a preview refresh.
*
* @since 1.3.3
* @access private
* @property {Object} _xhr
*/
_xhr : null,
/**
* Initializes a builder preview.
*
* @since 1.3.3
* @access private
* @method _init
*/
_init: function()
{
// Node Id
this.nodeId = $('.fl-builder-settings', window.parent.document).data('node');
// Save settings
this._saveSettings();
// Elements and Class Names
this._initElementsAndClasses();
// Create the preview stylesheets
this._createSheets();
// Responsive previews
this._initResponsivePreviews();
// Default field previews
this._initDefaultFieldPreviews();
// Init
switch(this.type) {
case 'row':
this._initRow();
break;
case 'col':
this._initColumn();
break;
case 'module':
this._initModule();
break;
}
FLBuilder.triggerHook( 'preview-init', this );
},
/**
* Saves the current settings to be checked to see if
* anything has changed when a preview is canceled.
*
* @since 1.7
* @access private
* @method _saveSettings
*/
_saveSettings: function()
{
var form = $('.fl-builder-settings-lightbox .fl-builder-settings', window.parent.document);
this._savedSettings = FLBuilder._getSettingsForChangedCheck( this.nodeId, form );
},
/**
* Checks to see if the settings have changed.
*
* @since 1.7
* @access private
* @method _settingsHaveChanged
* @return bool
*/
_settingsHaveChanged: function()
{
var form = $('.fl-builder-settings-lightbox .fl-builder-settings', window.parent.document),
settings = FLBuilder._getSettings( form );
return JSON.stringify( this._savedSettings ) != JSON.stringify( settings );
},
/**
* Initializes the classname and element references
* for this preview.
*
* @since 1.3.3
* @access private
* @method _initElementsAndClasses
*/
_initElementsAndClasses: function()
{
var contentClass;
// Content Class
if(this.type == 'row') {
contentClass = '.fl-row-content-wrap';
}
else {
contentClass = '.fl-' + this.type + '-content';
}
// Class Names
$.extend(this.classes, {
settings : '.fl-builder-' + this.type + '-settings',
settingsHeader : '.fl-builder-' + this.type + '-settings .fl-lightbox-header',
node : FLBuilder._contentClass + ' .fl-node-' + this.nodeId,
content : FLBuilder._contentClass + ' .fl-node-' + this.nodeId + ' > ' + contentClass
});
// Elements
$.extend(this.elements, {
settings : $(this.classes.settings, window.parent.document),
settingsHeader : $(this.classes.settingsHeader, window.parent.document),
node : $(this.classes.node),
content : $(this.classes.content)
});
},
/**
* Creates the stylesheets for default, medium
* and responsive previews.
*
* @since 1.9
* @method _createSheets
*/
_createSheets: function()
{
this._destroySheets();
if ( ! this._styleSheet ) {
this._styleSheet = new FLStyleSheet( {
id : 'fl-builder-preview',
className : 'fl-builder-preview-style'
} );
}
if ( ! this._styleSheetLarge) {
this._styleSheetLarge = new FLStyleSheet( {
id : 'fl-builder-preview-large',
className : 'fl-builder-preview-style'
} );
this._styleSheetLarge.disable();
}
if ( ! this._styleSheetMedium ) {
this._styleSheetMedium = new FLStyleSheet( {
id : 'fl-builder-preview-medium',
className : 'fl-builder-preview-style'
} );
this._styleSheetMedium.disable();
}
if ( ! this._styleSheetResponsive ) {
this._styleSheetResponsive = new FLStyleSheet( {
id : 'fl-builder-preview-responsive',
className : 'fl-builder-preview-style'
} );
this._styleSheetResponsive.disable();
}
},
/**
* Destroys all preview sheets.
*
* @since 1.9
* @method _destroySheets
*/
_destroySheets: function()
{
if ( this._styleSheet ) {
this._styleSheet.destroy();
this._styleSheet = null;
}
if ( this._styleSheetLarge ) {
this._styleSheetLarge.destroy();
this._styleSheetLarge = null;
}
if ( this._styleSheetMedium ) {
this._styleSheetMedium.destroy();
this._styleSheetMedium = null;
}
if ( this._styleSheetResponsive ) {
this._styleSheetResponsive.destroy();
this._styleSheetResponsive = null;
}
$( '.fl-builder-preview-style' ).remove();
},
/**
* Disables preview styles for the current
* responsive editing mode.
*
* @since 2.2
* @method _disableStyles
*/
_disableStyles: function()
{
var mode = FLBuilderResponsiveEditing._mode,
config = FLBuilderConfig.global,
node = this.elements.node;
if ( 'responsive' === mode ) {
FLBuilderSimulateMediaQuery.disableStyles( config.responsive_breakpoint );
this._styleSheetResponsive.disable();
} else if ( 'large' === mode ) {
FLBuilderSimulateMediaQuery.disableStyles( config.large_breakpoint );
this._styleSheetLarge.disable();
} else if ( 'medium' === mode ) {
FLBuilderSimulateMediaQuery.disableStyles( config.medium_breakpoint );
this._styleSheetMedium.disable();
} else {
node.removeClass( function( i, className ) {
return ( className.match( /fl-node-[^\s]*/g ) || [] ).join( ' ' );
} );
}
},
/**
* Enables preview styles for the current
* responsive editing mode.
*
* @since 2.2
* @method _enableStyles
*/
_enableStyles: function()
{
var mode = FLBuilderResponsiveEditing._mode,
node = this.elements.node;
if ( 'responsive' === mode ) {
FLBuilderSimulateMediaQuery.enableStyles();
this._styleSheetResponsive.enable();
} else if ( 'medium' === mode ) {
FLBuilderSimulateMediaQuery.enableStyles();
this._styleSheetMedium.enable();
} else if ( 'large' === mode ) {
FLBuilderSimulateMediaQuery.enableStyles();
this._styleSheetLarge.enable();
} else {
node.addClass( 'fl-node-' + node.data( 'node' ) );
}
},
/**
* Attempt to find the default value for a CSS property.
*
* @since 2.2
* @method _getDefaultValue
* @param {String} selector
* @param {String} property
* @return {String}
*/
_getDefaultValue: function( selector, property )
{
var value = '',
element = $( selector ),
node = element.closest( '[data-node]' ),
ignore = [ 'line-height', 'font-weight' ];
if ( 'width' === property ) {
value = 'auto';
} else if ( -1 === $.inArray( property, ignore ) && node.length ) {
this._disableStyles();
value = element.css( property );
this._enableStyles();
}
return value;
},
/**
* Updates a CSS rule for this preview.
*
* @since 1.3.3
* @method updateCSSRule
* @param {String} selector The CSS selector to update.
* @param {String} property The CSS property to update.
* @param {String} value The CSS value to update.
* @param {String|Boolean} responsive If this preview is responsive or not.
*/
updateCSSRule: function( selector, property, value, responsive )
{
var mode = FLBuilderResponsiveEditing._mode,
sheetKey = '';
// Get the default value if needed.
if ( '' === value || 'null' === value ) {
value = this._getDefaultValue( selector, property );
}
// Update the rule.
if ( responsive ) {
if ( 'string' === typeof responsive ) {
sheetKey = this.toUpperCaseWords( responsive );
} else {
sheetKey = 'default' === mode ? '' : this.toUpperCaseWords( mode );
}
this[ '_styleSheet' + sheetKey ].updateRule( selector, property, value );
} else {
this._styleSheet.updateRule( selector, property, value );
}
},
/**
* Runs a delay with a callback.
*
* @since 1.3.3
* @method delay
* @param {Number} length How long to wait before running the callback.
* @param {Function} callback A function to call when the delay is complete.
*/
delay: function(length, callback)
{
this._cancelDelay();
this._timeout = setTimeout(callback, length);
},
/**
* Cancels a preview refresh delay.
*
* @since 1.3.3
* @access private
* @method _cancelDelay
*/
_cancelDelay: function()
{
if(this._timeout !== null) {
clearTimeout(this._timeout);
}
},
/**
* Converts a hex value to an array of RGB values.
*
* @since 1.3.3
* @method hexToRgb
* @param {String} hex
* @return {Array}
*/
hexToRgb: function(hex)
{
var bigInt = parseInt(hex, 16),
r = (bigInt >> 16) & 255,
g = (bigInt >> 8) & 255,
b = bigInt & 255;
return [r, g, b];
},
/**
* Returns a hex or rgb formatted value.
*
* @since 2.0.3
* @method hexOrRgb
* @param {String} value
* @return {String}
*/
hexOrRgb: function( value )
{
if ( value.indexOf( 'rgb' ) < 0 && value.indexOf( '#' ) < 0 ) {
value = '#' + value;
}
return value;
},
/**
* Parses a float or returns 0 if we don't have a number.
*
* @since 1.3.3
* @method parseFloat
* @param {Number} value
* @return {Number}
*/
parseFloat: function(value)
{
return isNaN(parseFloat(value)) ? 0 : parseFloat(value);
},
/* Responsive Previews
----------------------------------------------------------*/
/**
* Initializes logic for responsive previews.
*
* @since 1.9
* @method _initResponsivePreviews
*/
_initResponsivePreviews: function()
{
var namespace = '.preview-' + this.id;
FLBuilder.addHook( 'responsive-editing-switched' + namespace, $.proxy( this._responsiveEditingSwitched, this ) );
FLBuilder.addHook( 'responsive-editing-before-preview-fields' + namespace, $.proxy( this._responsiveEditingPreviewFields, this ) );
},
/**
* Destroys responsive preview events.
*
* @since 1.9
* @method _destroyResponsivePreviews
*/
_destroyResponsivePreviews: function()
{
var namespace = '.preview-' + this.id;
FLBuilder.removeHook( 'responsive-editing-switched' + namespace );
FLBuilder.removeHook( 'responsive-editing-before-preview-fields' + namespace );
},
/**
* Initializes logic for responsive previews.
*
* @since 1.9
* @method _responsiveEditingSwitched
*/
_responsiveEditingSwitched: function( e, mode )
{
if ( 'default' == mode ) {
this._styleSheetLarge.disable();
this._styleSheetMedium.disable();
this._styleSheetResponsive.disable();
}
else if ( 'large' == mode ) {
this._styleSheetLarge.enable();
this._styleSheetMedium.disable();
this._styleSheetResponsive.disable();
}
else if ( 'medium' == mode ) {
this._styleSheetLarge.enable();
this._styleSheetMedium.enable();
this._styleSheetResponsive.disable();
}
else if ( 'responsive' == mode ) {
this._styleSheetLarge.enable();
this._styleSheetMedium.enable();
this._styleSheetResponsive.enable();
}
},
/**
* Logic that needs to run before field previews are triggered
* after responsive editing mode switches.
*
* @since 2.2
* @method _responsiveEditingPreviewFields
*/
_responsiveEditingPreviewFields: function( e, mode )
{
if ( 'large' === mode || 'medium' === mode ) {
if ( 'col' === this.type && this.elements.node[0].style.width ) {
size = parseFloat( this.elements.node[0].style.width );
this.elements.size.val( size );
}
}
},
/**
* Deprecated. Use updateCSSRule instead.
*
* @since 1.9
*/
updateResponsiveCSSRule: function( selector, property, value )
{
this.updateCSSRule( selector, property, value, true );
},
/* States
----------------------------------------------------------*/
/**
* Saves the current state of a layout.
*
* @since 1.3.3
* @access private
* @method _saveState
*/
_saveState: function()
{
var post = FLBuilderConfig.postId,
css = $('link[href*="/cache/' + post + '"]').attr('href'),
js = $('script[src*="/cache/' + post + '"]').attr('src'),
html = $(FLBuilder._contentClass).html();
this.state = {
css : css,
js : js,
html : html
};
},
/**
* Runs a preview refresh for the current settings lightbox.
*
* @since 1.3.3
* @method preview
*/
preview: function()
{
var form = $('.fl-builder-settings-lightbox .fl-builder-settings', window.parent.document),
nodeId = form.attr('data-node'),
settings = FLBuilder._getSettings(form);
// Show the node as loading.
FLBuilder._showNodeLoading( nodeId );
// Abort an existing preview request.
this._cancelPreview();
settings = FLBuilder._inputVarsCheck( settings );
if ( 'error' === settings ) {
return 0;
}
// Make a new preview request.
this._xhr = FLBuilder.ajax({
action : 'render_layout',
node_id : nodeId,
node_preview : settings
}, $.proxy(this._renderPreview, this));
},
/**
* Runs a preview refresh with a delay.
*
* @since 1.3.3
* @method delayPreview
*/
delayPreview: function(e)
{
var heading = typeof e == 'undefined' ? [] : $(e.target).closest('tr').find('th'),
widgetHeading = $('.fl-builder-widget-settings .fl-builder-settings-title', window.parent.document),
lightboxHeading = $('.fl-builder-settings .fl-lightbox-header', window.parent.document),
loaderSrc = FLBuilderLayoutConfig.paths.pluginUrl + 'img/ajax-loader-small.svg',
loader = $('');
this.delay(1000, $.proxy(this.preview, this));
this._loaderTimeout = setTimeout( function() {
$('.fl-builder-preview-loader', window.parent.document).remove();
if(heading.length > 0) {
heading.append(loader);
}
else if(widgetHeading.length > 0) {
widgetHeading.append(loader);
}
else if(lightboxHeading.length > 0) {
lightboxHeading.append(loader);
}
}, 1500 );
},
/**
* Cancels a preview refresh.
*
* @since 1.3.3
* @access private
* @method _cancelPreview
*/
_cancelPreview: function()
{
if(this._xhr) {
this._xhr.abort();
this._xhr = null;
}
},
/**
* Renders the response of a preview refresh.
*
* @since 1.3.3
* @access private
* @method _renderPreview
* @param {String} response The JSON encoded response.
*/
_renderPreview: function(response)
{
this._xhr = null;
FLBuilder._renderLayout(response, $.proxy(this._renderPreviewComplete, this));
},
/**
* Fires when a preview refresh has finished rendering.
*
* @since 1.3.3
* @access private
* @method _renderPreviewComplete
*/
_renderPreviewComplete: function()
{
// Refresh the preview styles.
this._createSheets();
// Refresh the elements.
this._initElementsAndClasses();
// Refresh preview config for element references.
this._initDefaultFieldPreviews();
// Clear the loader timeout.
if(this._loaderTimeout !== null) {
clearTimeout(this._loaderTimeout);
}
/**
* Remove the loading graphic
* 2.6.0.2 added 500ms delay to fix #2234
*/
setTimeout( function() {
$('.fl-builder-preview-loader', window.parent.document).remove();
}, 500 );
// Fire the preview rendered event.
$( FLBuilder._contentClass ).trigger( 'fl-builder.preview-rendered' );
},
/**
* Reverts a preview to the state that was saved
* before the preview was initialized.
*
* @since 1.3.3
* @method revert
*/
revert: function()
{
var nodeId = this.nodeId;
if ( ! this._settingsHaveChanged() ) {
this.clear();
return;
}
if ( 'col' === this.type ) {
nodeId = this.elements.node.closest( '.fl-col-group' ).data( 'node' );
}
FLBuilder._updateNode( nodeId, function() {
this.clear();
}.bind( this ) );
},
/**
* Cancels a preview refresh.
*
* @since 1.3.3
* @method clear
*/
cancel: function()
{
this._cancelDelay();
this._cancelPreview();
},
/**
* Cancels a preview refresh and removes
* any stylesheet changes.
*
* @since 1.3.3
* @method clear
*/
clear: function()
{
// Canel any preview delays or requests.
this.cancel();
// Destroy the preview stylesheet.
this._destroySheets();
// Destroy responsive editing previews.
this._destroyResponsivePreviews();
},
/* Node Text Color Settings
----------------------------------------------------------*/
/**
* Initializes node text color previews.
*
* @since 1.3.3
* @access private
* @method _initNodeTextColor
*/
_initNodeTextColor: function()
{
// Elements
$.extend(this.elements, {
textColor : $(this.classes.settings + ' input[name=text_color]', window.parent.document),
linkColor : $(this.classes.settings + ' input[name=link_color]', window.parent.document),
hoverColor : $(this.classes.settings + ' input[name=hover_color]', window.parent.document),
headingColor : $(this.classes.settings + ' input[name=heading_color]', window.parent.document)
});
// Events
this.elements.textColor.on('change', $.proxy(this._textColorChange, this));
this.elements.linkColor.on('change', $.proxy(this._textColorChange, this));
this.elements.hoverColor.on('change', $.proxy(this._textColorChange, this));
this.elements.headingColor.on('change', $.proxy(this._textColorChange, this));
},
/**
* Fires when the text color field for a node
* is changed.
*
* @since 1.3.3
* @access private
* @method _textColorChange
* @param {Object} e An event object.
*/
_textColorChange: function(e)
{
var textColor = this.elements.textColor.val(),
linkColor = this.elements.linkColor.val(),
hoverColor = this.elements.hoverColor.val(),
headingColor = this.elements.headingColor.val();
linkColor = linkColor === '' ? textColor : linkColor;
hoverColor = hoverColor === '' ? textColor : hoverColor;
headingColor = headingColor === '' ? textColor : headingColor;
if ( textColor && textColor.indexOf( 'rgb' ) < 0 ) {
textColor = '#' + textColor;
}
if ( linkColor && linkColor.indexOf( 'rgb' ) < 0 ) {
linkColor = '#' + linkColor;
}
if ( hoverColor && hoverColor.indexOf( 'rgb' ) < 0 ) {
hoverColor = '#' + hoverColor;
}
if ( headingColor && headingColor.indexOf( 'rgb' ) < 0 ) {
headingColor = '#' + headingColor;
}
this.delay(50, $.proxy(function(){
// Update Text color.
if(textColor === '') {
this.updateCSSRule(this.classes.node, 'color', '');
}
else {
this.updateCSSRule(this.classes.node, 'color', textColor);
}
// Update Link Color
if ( linkColor === '' ) {
this.updateCSSRule(this.classes.node + ' a', 'color', '');
}
else {
this.updateCSSRule(this.classes.node + ' a', 'color', linkColor);
}
// Hover Color
if(hoverColor === '') {
this.updateCSSRule(this.classes.node + ' a:hover', 'color', '');
}
else {
this.updateCSSRule(this.classes.node + ' a:hover', 'color', hoverColor);
}
// Heading Color
if(headingColor === '') {
this.updateCSSRule(this.classes.node + ' h1', 'color', '');
this.updateCSSRule(this.classes.node + ' h2', 'color', '');
this.updateCSSRule(this.classes.node + ' h3', 'color', '');
this.updateCSSRule(this.classes.node + ' h4', 'color', '');
this.updateCSSRule(this.classes.node + ' h5', 'color', '');
this.updateCSSRule(this.classes.node + ' h6', 'color', '');
this.updateCSSRule(this.classes.node + ' h1 a', 'color', '');
this.updateCSSRule(this.classes.node + ' h2 a', 'color', '');
this.updateCSSRule(this.classes.node + ' h3 a', 'color', '');
this.updateCSSRule(this.classes.node + ' h4 a', 'color', '');
this.updateCSSRule(this.classes.node + ' h5 a', 'color', '');
this.updateCSSRule(this.classes.node + ' h6 a', 'color', '');
}
else {
this.updateCSSRule(this.classes.node + ' h1', 'color', headingColor);
this.updateCSSRule(this.classes.node + ' h2', 'color', headingColor);
this.updateCSSRule(this.classes.node + ' h3', 'color', headingColor);
this.updateCSSRule(this.classes.node + ' h4', 'color', headingColor);
this.updateCSSRule(this.classes.node + ' h5', 'color', headingColor);
this.updateCSSRule(this.classes.node + ' h6', 'color', headingColor);
this.updateCSSRule(this.classes.node + ' h1 a', 'color', headingColor);
this.updateCSSRule(this.classes.node + ' h2 a', 'color', headingColor);
this.updateCSSRule(this.classes.node + ' h3 a', 'color', headingColor);
this.updateCSSRule(this.classes.node + ' h4 a', 'color', headingColor);
this.updateCSSRule(this.classes.node + ' h5 a', 'color', headingColor);
this.updateCSSRule(this.classes.node + ' h6 a', 'color', headingColor);
}
}, this));
},
/* Node Bg Settings
----------------------------------------------------------*/
/**
* Initializes node background previews.
*
* @since 1.3.3
* @access private
* @method _initNodeBg
*/
_initNodeBg: function()
{
// Elements
$.extend(this.elements, {
bgType : $(this.classes.settings + ' select[name=bg_type]', window.parent.document),
bgColor : $(this.classes.settings + ' input[name=bg_color]', window.parent.document),
bgColorPicker : $(this.classes.settings + ' .fl-picker-bg_color', window.parent.document),
bgGradientType : $(this.classes.settings + ' select.fl-gradient-picker-type-select', window.parent.document),
bgVideoSource : $(this.classes.settings + ' select[name=bg_video_source]', window.parent.document),
bgVideo : $(this.classes.settings + ' input[name=bg_video]', window.parent.document),
bgVideoServiceUrl : $(this.classes.settings + ' input[name=bg_video_service_url]', window.parent.document),
bgVideoFallbackSrc : $(this.classes.settings + ' select[name=bg_video_fallback_src]', window.parent.document),
bgSlideshowSource : $(this.classes.settings + ' select[name=ss_source]', window.parent.document),
bgSlideshowPhotos : $(this.classes.settings + ' input[name=ss_photos]', window.parent.document),
bgSlideshowFeedUrl : $(this.classes.settings + ' input[name=ss_feed_url]', window.parent.document),
bgSlideshowSpeed : $(this.classes.settings + ' input[name=ss_speed]', window.parent.document),
bgSlideshowTrans : $(this.classes.settings + ' select[name=ss_transition]', window.parent.document),
bgSlideshowTransSpeed : $(this.classes.settings + ' input[name=ss_transitionDuration]', window.parent.document),
bgParallaxImageSrc : $(this.classes.settings + ' select[name=bg_parallax_image_src]', window.parent.document),
bgOverlayType : $(this.classes.settings + ' select[name=bg_overlay_type]', window.parent.document),
bgOverlayColor : $(this.classes.settings + ' input[name=bg_overlay_color]', window.parent.document),
bgOverlayGradient : $(this.classes.settings + ' #fl-field-bg_overlay_gradient select', window.parent.document),
});
// Events
this.elements.bgType.on( 'change', $.proxy(this._bgTypeChange, this));
this.elements.bgColor.on( 'change', $.proxy(this._bgColorChange, this));
this.elements.bgVideoServiceUrl.on( 'change', $.proxy(this._bgVideoChange, this));
this.elements.bgSlideshowSource.on( 'change', $.proxy(this._bgSlideshowChange, this));
this.elements.bgSlideshowPhotos.on( 'change', $.proxy(this._bgSlideshowChange, this));
this.elements.bgSlideshowFeedUrl.on( 'keyup', $.proxy(this._bgSlideshowChange, this));
this.elements.bgSlideshowSpeed.on( 'keyup', $.proxy(this._bgSlideshowChange, this));
this.elements.bgSlideshowTrans.on( 'change', $.proxy(this._bgSlideshowChange, this));
this.elements.bgSlideshowTransSpeed.on( 'keyup', $.proxy(this._bgSlideshowChange, this));
this.elements.bgParallaxImageSrc.on( 'change', $.proxy(this._bgParallaxChange, this));
this.elements.bgOverlayType.on( 'change', $.proxy(this._bgOverlayChange, this));
this.elements.bgOverlayColor.on( 'change', $.proxy(this._bgOverlayChange, this));
},
/**
* Fires when the background type field of
* a node changes.
*
* @since 1.3.3
* @access private
* @method _bgTypeChange
* @param {Object} e An event object.
*/
_bgTypeChange: function(e)
{
var val = this.elements.bgType.val(),
mode = FLBuilderResponsiveEditing._mode;
// Clear bg styles first.
this.elements.node.removeClass('fl-row-bg-video');
this.elements.node.removeClass('fl-row-bg-slideshow');
this.elements.node.removeClass('fl-row-bg-parallax');
this.elements.node.find('.fl-bg-video').remove();
this.elements.node.find('.fl-bg-slideshow').remove();
this.elements.content.css('background-image', '');
this.updateCSSRule(this.classes.content, 'background-color', 'transparent');
this.updateCSSRule(this.classes.content, 'background-image', 'none');
this.updateCSSRule(this.classes.content, 'background-image', 'none', 'medium');
this.updateCSSRule(this.classes.content, 'background-image', 'none', 'responsive');
// None
if(val == 'none') {
this._bgOverlayClear();
}
// Color
else if(val == 'color') {
this.elements.bgColor.trigger('change');
this._bgOverlayClear();
}
// Gradient
else if(val == 'gradient') {
this.elements.bgGradientType.trigger('change');
this._bgOverlayClear();
}
// Photo
else if(val == 'photo') {
this.elements.bgColor.trigger('change');
this.elements.settings.find( '[data-device="' + mode + '"] select[name*="bg_"]' ).trigger( 'change' );
}
// Video
else if(val == 'video') {
this.elements.bgColor.trigger('change');
this._bgVideoChange();
}
// Slideshow
else if(val == 'slideshow') {
this.elements.bgColor.trigger('change');
this._bgSlideshowChange();
}
// Parallax
else if(val == 'parallax') {
this.elements.bgColor.trigger('change');
this.elements.bgParallaxImageSrc.trigger('change');
}
},
/**
* Fires when the background color field of
* a node changes.
*
* @since 1.3.3
* @access private
* @method _bgColorChange
* @param {Object} e An event object.
*/
_bgColorChange: function(e)
{
var rgb, alpha, value;
if(this.elements.bgColor.val() === '') {
this.updateCSSRule(this.classes.content, 'background-color', 'transparent');
}
else {
value = this.hexOrRgb( this.elements.bgColor.val() );
this.delay(100, $.proxy(function(){
this.updateCSSRule(this.classes.content, 'background-color', value);
}, this));
}
},
/**
* Fires when the background video field of
* a node changes.
*
* @since 1.9.2
* @access private
* @method _bgVideoChange
* @param {Object} e An event object.
*/
_bgVideoChange: function(e)
{
var eles = this.elements,
source = eles.bgVideoSource.val(),
video = eles.bgVideo.val(),
videoUrl = eles.bgVideoServiceUrl.val(),
youtubePlayer = 'https://www.youtube.com/iframe_api',
vimeoPlayer = 'https://player.vimeo.com/api/player.js',
scriptTag = $( '