(function($){
/**
* Custom lightbox for builder popups.
*
* @class FLLightbox
* @since 1.0
*/
FLLightbox = function( settings )
{
this._init( settings );
};
/**
* Closes the lightbox of a child element that
* is passed to this method.
*
* @since 1.0
* @static
* @method closeParent
* @param {Object} child An HTML element or jQuery reference to an element.
*/
FLLightbox.closeParent = function( child )
{
var instanceId = $( child ).closest( '.fl-lightbox-wrap' ).attr( 'data-instance-id' );
if ( ! _.isUndefined( instanceId ) ) {
FLLightbox._instances[ instanceId ].close();
}
};
/**
* Returns the classname for the resize control in lightbox headers.
*
* @since 2.0
* @static
* @method getResizableControlClass
* @return {String}
*/
FLLightbox.getResizableControlClass = function()
{
var resizable = $( '.fl-lightbox-resizable', window.parent.document ).eq( 0 ),
className = 'far fa-window-maximize';
if ( resizable.length && resizable.hasClass( 'fl-lightbox-width-full' ) ) {
className = 'far fa-window-minimize';
}
return className;
};
/**
* Unbinds events for all lightbox instances.
*
* @since 2.0
* @static
* @method unbindAll
*/
FLLightbox.unbindAll = function()
{
var id;
for ( id in FLLightbox._instances ) {
FLLightbox._instances[ id ]._unbind();
}
};
/**
* Binds events for all lightbox instances.
*
* @since 2.0
* @static
* @method bindAll
*/
FLLightbox.bindAll = function()
{
var id;
for ( id in FLLightbox._instances ) {
FLLightbox._instances[ id ]._bind();
}
};
/**
* Close all lightbox instances.
*
* @since 2.0
* @static
* @method closeAll
*/
FLLightbox.closeAll = function()
{
var id;
for ( id in FLLightbox._instances ) {
FLLightbox._instances[ id ].close();
}
};
/**
* An object that stores a reference to each
* lightbox instance that is created.
*
* @since 1.0
* @static
* @access private
* @property {Object} _instances
*/
FLLightbox._instances = {};
/**
* Prototype for new instances.
*
* @since 1.0
* @property {Object} prototype
*/
FLLightbox.prototype = {
/**
* A unique ID for this instance that's used to store
* it in the static _instances object.
*
* @since 1.0
* @access private
* @property {String} _id
*/
_id: null,
/**
* A jQuery reference to the main wrapper div.
*
* @since 1.0
* @access private
* @property {Object} _node
*/
_node: null,
/**
* Flag for whether the lightbox is visible or not.
*
* @since 1.0
* @access private
* @property {Boolean} _visible
*/
_visible: false,
/**
* Whether closing the lightbox is allowed or not.
*
* @since 2.0
* @access private
* @property {Boolean} _allowClosing
*/
_allowClosing: true,
/**
* A timeout used to throttle the resize event.
*
* @since 1.0
* @access private
* @property {Object} _resizeTimer
*/
_resizeTimer: null,
/**
* Default config object.
*
* @since 1.0
* @access private
* @property {Object} _defaults
* @property {String} _defaults.className - A custom classname to add to the wrapper div.
* @property {Boolean} _defaults.destroyOnClose - Flag for whether the instance should be destroyed when closed.
* @property {Boolean} _defaults.resizable - Flag for Whether this instance should be resizable or not.
*/
_defaults: {
className: '',
destroyOnClose: false,
resizable: false
},
/**
* Opens the lightbox. You can pass new content to this method.
* If no content is passed, the previous content will be shown.
*
* @since 1.0
* @method open
* @param {String} content HTML content to add to the lightbox.
*/
open: function(content)
{
var lightbox = this._node.find( '.fl-lightbox' ),
isPinned = ( lightbox.closest( '.fl-builder-ui-pinned' ).length ),
settings = this._getPositionSettings();
if ( ! isPinned && settings && this._defaults.resizable ) {
lightbox.css( settings );
}
this._bind();
this._node.show();
this._visible = true;
if(typeof content !== 'undefined') {
this.setContent(content);
}
else {
this._resize();
}
this.trigger('open');
FLBuilder.triggerHook('didShowLightbox', this);
},
/**
* Closes the lightbox.
*
* @since 1.0
* @method close
*/
close: function()
{
var parent = this._node.data('parent');
if ( ! this._allowClosing ) {
return;
}
this.trigger('beforeCloseLightbox');
this._unbind();
this._node.hide();
this._visible = false;
this.trigger('close');
FLBuilder.triggerHook('didHideLightbox');
if ( this._defaults.resizable && _.isUndefined( parent ) ) {
FLBuilder.triggerHook('didHideAllLightboxes');
}
if(this._defaults.destroyOnClose) {
this.destroy();
}
},
/**
* Disables closing the lightbox.
*
* @since 2.0
* @method disableClose
*/
disableClose: function()
{
this._allowClosing = false;
},
/**
* Enables closing the lightbox.
*
* @since 2.0
* @method enableClose
*/
enableClose: function()
{
this._allowClosing = true;
},
/**
* Adds HTML content to the lightbox replacing any
* previously added content.
*
* @since 1.0
* @method setContent
* @param {String} content HTML content to add to the lightbox.
*/
setContent: function(content)
{
this._node.find('.fl-lightbox-content').html(content);
this._resize();
if( $( '.fl-builder-content-panel-button', window.parent.document ).length == 0 ) {
$( '.fl-builder-panel-drag-handle', window.parent.document ).show();
}
},
/**
* Uses the jQuery empty function to remove lightbox
* content and any related events.
*
* @since 1.0
* @method empty
*/
empty: function()
{
this._node.find('.fl-lightbox-content').empty();
},
/**
* Bind an event to the lightbox.
*
* @since 1.0
* @method on
* @param {String} event The type of event to bind.
* @param {Function} callback A callback to fire when the event is triggered.
*/
on: function(event, callback)
{
this._node.on(event, callback);
},
/**
* Unbind an event from the lightbox.
*
* @since 1.0
* @method off
* @param {String} event The type of event to unbind.
* @param {Function} callback
*/
off: function(event, callback)
{
this._node.off(event, callback);
},
/**
* Trigger an event on the lightbox.
*
* @since 1.0
* @method trigger
* @param {String} event The type of event to trigger.
* @param {Object} params Additional parameters to pass to the event.
*/
trigger: function(event, params)
{
this._node.trigger(event, params);
},
/**
* Destroy the lightbox by removing all elements, events
* and object references.
*
* @since 1.0
* @method destroy
*/
destroy: function()
{
this._node.empty();
this._node.remove();
FLLightbox._instances[this._id] = 'undefined';
try{ delete FLLightbox._instances[this._id]; } catch(e){}
},
/**
* Initialize this lightbox instance.
*
* @since 1.0
* @access private
* @method _init
* @param {Object} settings A setting object for this instance.
*/
_init: function(settings)
{
var i = 0,
prop = null;
for(prop in FLLightbox._instances) {
i++;
}
this._defaults = $.extend({}, this._defaults, settings);
this._id = new Date().getTime() + i;
FLLightbox._instances[this._id] = this;
this._render();
this._resizable();
},
/**
* Renders the main wrapper.
*
* @since 1.0
* @access private
* @method _render
*/
_render: function()
{
this._node = $( '
' );
this._node.addClass( this._defaults.className );
$( 'body', window.parent.document ).append( this._node );
},
/**
* Binds events for this instance.
*
* @since 1.0
* @access private
* @method _bind
*/
_bind: function()
{
$( window.parent ).on( 'resize.fl-lightbox-' + this._id, this._delayedResize.bind( this ) );
},
/**
* Unbinds events for this instance.
*
* @since 1.0
* @access private
* @method _unbind
*/
_unbind: function()
{
$( window.parent ).off( 'resize.fl-lightbox-' + this._id );
},
/**
* Enable resizing for the lightbox.
*
* @since 2.0
* @method _resizable
*/
_resizable: function()
{
var body = $( 'body', window.parent.document ),
mask = this._node.find( '.fl-lightbox-mask' ),
lightbox = this._node.find( '.fl-lightbox' ),
resizable = $( '.fl-lightbox-resizable', window.parent.document ).eq( 0 );
if ( this._defaults.resizable ) {
mask.hide();
lightbox.addClass( 'fl-lightbox-resizable' );
lightbox.on( 'click', '.fl-lightbox-resize-toggle', this._resizeClicked.bind( this ) );
lightbox.draggable( {
cursor : 'move',
handle : '.fl-lightbox-header',
iframeFix : true
} ).resizable( {
handles : 'all',
minHeight : 500,
minWidth : 380,
start : this._resizeStart.bind( this ),
stop : this._resizeStop.bind( this )
} );
if ( resizable.length && resizable.hasClass( 'fl-lightbox-width-full' ) ) { // Setup nested
lightbox.addClass( 'fl-lightbox-width-full' );
lightbox.draggable( 'disable' );
} else { // Setup the main parent lightbox
this._restorePosition();
}
}
else {
mask.show();
}
this._resize();
},
/**
* Resizes the lightbox after a delay.
*
* @since 1.0
* @access private
* @method _delayedResize
*/
_delayedResize: function()
{
clearTimeout( this._resizeTimer );
this._resizeTimer = setTimeout( this._resize.bind( this ), 250 );
},
/**
* Resizes the lightbox.
*
* @since 1.0
* @access private
* @method _resize
*/
_resize: function()
{
var lightbox = this._node.find( '.fl-lightbox' ),
boxTop = parseInt( this._node.css( 'padding-top' ) ),
boxBottom = parseInt( this._node.css( 'padding-bottom' ) ),
boxLeft = parseInt( this._node.css( 'padding-left' ) ),
boxRight = parseInt( this._node.css( 'padding-right' ) ),
boxHeight = lightbox.height(),
boxWidth = lightbox.width(),
win = $( window.parent ),
winHeight = win.height() - boxTop - boxBottom,
winWidth = win.width() - boxLeft - boxRight,
top = '0px';
if ( ! this._defaults.resizable ) {
if ( winHeight > boxHeight ) {
top = ( ( winHeight - boxHeight - 46 ) / 2 ) + 'px';
}
lightbox.attr( 'style', '' ).css( 'margin', top + ' auto 0' );
}
else {
if ( boxWidth < 600 ) {
lightbox.addClass( 'fl-lightbox-width-slim' );
} else {
lightbox.removeClass( 'fl-lightbox-width-slim' );
}
if ( boxWidth < 450 ) {
lightbox.addClass( 'fl-lightbox-width-micro' );
} else {
lightbox.removeClass( 'fl-lightbox-width-micro' );
}
this._resizeEditors();
}
this.trigger( 'resized' );
},
/**
* Callback for when a user lightbox resize starts.
*
* @since 2.0
* @access private
* @method _resizeStart
*/
_resizeStart: function()
{
$( 'body', window.parent.document ).addClass( 'fl-builder-resizable-is-resizing' );
$( '.fl-builder-lightbox:visible', window.parent.document ).append( '' );
FLBuilder._destroyOverlayEvents();
FLBuilder._removeAllOverlays();
},
/**
* Callback for when a user lightbox resize stops.
*
* @since 2.0
* @access private
* @method _resizeStop
*/
_resizeStop: function( e, ui )
{
var lightbox = $( '.fl-lightbox-resizable:visible', window.parent.document );
if ( parseInt( lightbox.css( 'top' ) ) < 0 ) {
lightbox.css( 'top', '0' );
}
this._savePosition();
$( 'body', window.parent.document ).removeClass( 'fl-builder-resizable-is-resizing' );
$( '.fl-builder-resizable-iframe-fix', window.parent.document ).remove();
FLBuilder._bindOverlayEvents();
},
/**
* Resize to full or back to standard when the resize icon is clicked.
*
* @since 2.0
* @access private
* @method _expandLightbox
*/
_resizeClicked: function()
{
var lightboxes = $( '.fl-lightbox-resizable', window.parent.document ),
controls = lightboxes.find( '.fl-lightbox-resize-toggle' ),
lightbox = this._node.find( '.fl-lightbox' );
if ( lightbox.hasClass( 'fl-lightbox-width-full' ) ) {
this._resizeExitFull();
} else {
this._resizeEnterFull();
}
this._resize();
},
/**
* Resize to the full size lightbox.
*
* @since 2.0
* @access private
* @method _resizeEnterFull
*/
_resizeEnterFull: function()
{
var lightboxes = $( '.fl-lightbox-resizable', window.parent.document ),
controls = lightboxes.find( '.fl-lightbox-resize-toggle' ),
lightbox = this._node.find( '.fl-lightbox' );
controls.removeClass( 'fa-window-maximize' ).addClass( 'fa-window-minimize' );
lightboxes.addClass( 'fl-lightbox-width-full' );
lightboxes.draggable( 'disable' );
lightboxes.resizable( 'disable' );
},
/**
* Resize to the standard size lightbox.
*
* @since 2.0
* @access private
* @method _resizeEnterFull
*/
_resizeExitFull: function()
{
var lightboxes = $( '.fl-lightbox-resizable', window.parent.document ),
controls = lightboxes.find( '.fl-lightbox-resize-toggle' ),
lightbox = this._node.find( '.fl-lightbox' );
controls.removeClass( 'fa-window-minimize' ).addClass( 'fa-window-maximize' );
lightboxes.removeClass( 'fl-lightbox-width-full' );
lightboxes.draggable( 'enable' );
lightboxes.resizable( 'enable' );
},
/**
* Resizes text and code editor fields.
*
* @since 2.0
* @method _resizeEditors
*/
_resizeEditors: function()
{
$( '.fl-lightbox-resizable', window.parent.document ).each( function() {
var lightbox = $( this ),
fieldsHeight = lightbox.find( '.fl-builder-settings-fields' ).height(),
editors = lightbox.find( '.mce-edit-area > iframe, textarea.wp-editor-area, .ace_editor' ),
editor = null;
if ( fieldsHeight < 350 ) {
fieldsHeight = 350;
}
editors.each( function() {
editor = $( this );
if ( editor.hasClass( 'ace_editor' ) ) {
editor.height( fieldsHeight - 60 );
editor.closest( '.fl-field' ).data( 'editor' ).resize();
} else if ( editor.closest( '.mce-container-body' ).find( '.mce-toolbar-grp .mce-toolbar.mce-last' ).is( ':visible' ) ) {
editor.height( fieldsHeight - 175 );
} else {
editor.height( fieldsHeight - 150 );
}
} );
} );
},
/**
* Save the lightbox position for the current user.
*
* @since 2.0
* @access private
* @method _savePosition
*/
_savePosition: function()
{
var lightbox = this._node.find( '.fl-lightbox' ),
data = {
width : lightbox.width(),
height : lightbox.height(),
top : parseInt( lightbox.css( 'top' ) ) < 0 ? '0px' : lightbox.css( 'top' ),
left : lightbox.css( 'left' )
};
if ( lightbox.closest( '.fl-builder-ui-pinned' ).length ) {
return;
}
FLBuilderConfig.userSettings.lightbox = data;
FLBuilder.ajax( {
action : 'save_lightbox_position',
data : data
} );
},
/**
* Restores the lightbox position for the current user.
*
* @since 2.0
* @access private
* @method _restorePosition
*/
_restorePosition: function()
{
var lightbox = this._node.find( '.fl-lightbox' ),
settings = this._getPositionSettings();
if ( settings ) {
lightbox.css( settings );
} else {
lightbox.css( {
top : 25,
left : FLBuilderConfig.isRtl ? '-' + 25 : 25
} );
}
},
/**
* Get the user settings for the lightbox position.
*
* Resize the height to 500px if the lightbox height is
* taller than the window and the window is taller than
* 546px (500px for lightbox min-height and 46px for the
* builder bar height).
*
* @since 2.0
* @access private
* @method _getPositionSettings
* @return {Object|Boolean}
*/
_getPositionSettings: function()
{
var settings = FLBuilderConfig.userSettings.lightbox;
if ( ! settings ) {
return false;
}
var winHeight = window.parent.innerHeight,
isRTL = FLBuilderConfig.isRtl,
height = parseInt( settings.height ),
top = parseInt( settings.top ),
wleft = parseInt( settings.left ),
wtop = parseInt( settings.top ),
width = parseInt( settings.width );
// settings are off the screen to the right
if( ! isRTL && (wleft + width + 100) > screen.width ) {
settings.left = screen.width - width - 250;
}
// settings are off the screen to the left
if ( ! isRTL && wleft < 0 ) {
settings.left = 50;
}
wleft = parseInt( settings.left );
if ( isRTL && wleft > 0 ) {
settings.left = -25;
}
if ( ( height > winHeight && winHeight > 546 ) || top + height > winHeight ) {
if ( height > winHeight ) {
settings.height = winHeight - 50;
}
settings.top = 0;
}
return settings;
},
};
})(jQuery);