Snapshot: MLS sync fixes, image refresh, plugin/theme updates
MLS plugin fixes from this session: - Fix silent insert failures: location column NOT NULL was rejecting wpdb->insert calls, causing ~18k new properties since Dec 2025 to be lost. Inserts now build raw SQL with ST_PointFromText so the spatial column is populated atomically. - Auto-refresh expired media URLs in MLS_Media_Handler::fetch_and_cache(), guarded by a property-level GET_LOCK so concurrent fetches share one API refresh. - Normalize WP_Error to null in mls_get_property_image() so callers can rely on the documented string|null contract. - Support comma-separated property_type filters in MLS_Query and MLS_Cluster so the homepage "View All Commercial" link (?property_type=Commercial+Sale,Land,Farm) actually filters correctly. - Incremental sync now looks back 10 minutes past the latest modification timestamp as a safety margin against missed records. - Smart sync exits silently (info-level, not warning) when a full sync is in progress. Operational: - New cron: weekly full sync Sundays at 3 AM (/usr/local/bin/mls-full-sync). - New cron: hourly 2GB cap on mls-thumbnails/ and cache/transformed-images/ (/usr/local/bin/mls-image-cache-cap). - Logrotate config for wp-content/debug.log (2-day retention, daily rotation, delaycompress). Repo policy: - CLAUDE.md updated with explicit "commit everything except build artifacts" policy. - .gitignore: untrack runtime image caches and debug.log rotations. Other modifications in this snapshot are pre-existing in-flight theme/plugin/db_content_updates work. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
;( function( $ ) {
|
||||
|
||||
$( function() {
|
||||
|
||||
// Close modal.
|
||||
var wpformsModalClose = function() {
|
||||
|
||||
if ( $( '#wpforms-modal-select-form' ).length ) {
|
||||
$( '#wpforms-modal-select-form' ).get( 0 ).selectedIndex = 0;
|
||||
$( '#wpforms-modal-checkbox-title, #wpforms-modal-checkbox-description' ).prop( 'checked', false );
|
||||
}
|
||||
|
||||
$( '#wpforms-modal-backdrop, #wpforms-modal-wrap' ).css( 'display', 'none' );
|
||||
$( document.body ).removeClass( 'modal-open' );
|
||||
};
|
||||
|
||||
// Open modal when media button is clicked.
|
||||
$( document ).on( 'click', '.wpforms-insert-form-button', function( event ) {
|
||||
|
||||
event.preventDefault();
|
||||
$( '#wpforms-modal-backdrop, #wpforms-modal-wrap' ).css( 'display', 'block' );
|
||||
$( document.body ).addClass( 'modal-open' );
|
||||
} );
|
||||
|
||||
// Close modal on close or cancel links.
|
||||
$( document ).on( 'click', '#wpforms-modal-close, #wpforms-modal-cancel a', function( event ) {
|
||||
|
||||
event.preventDefault();
|
||||
wpformsModalClose();
|
||||
} );
|
||||
|
||||
// Insert shortcode into TinyMCE.
|
||||
$( document ).on( 'click', '#wpforms-modal-submit', function( event ) {
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
var shortcode;
|
||||
|
||||
shortcode = '[wpforms id="' + $( '#wpforms-modal-select-form' ).val() + '"';
|
||||
|
||||
if ( $( '#wpforms-modal-checkbox-title' ).is( ':checked' ) ) {
|
||||
shortcode = shortcode + ' title="true"';
|
||||
}
|
||||
|
||||
if ( $( '#wpforms-modal-checkbox-description' ).is( ':checked' ) ) {
|
||||
shortcode = shortcode + ' description="true"';
|
||||
}
|
||||
|
||||
shortcode = shortcode + ']';
|
||||
|
||||
wp.media.editor.insert( shortcode );
|
||||
wpformsModalClose();
|
||||
} );
|
||||
|
||||
} );
|
||||
|
||||
}( jQuery ) );
|
||||
+1
@@ -0,0 +1 @@
|
||||
(c=>{c(function(){function e(){c("#wpforms-modal-select-form").length&&(c("#wpforms-modal-select-form").get(0).selectedIndex=0,c("#wpforms-modal-checkbox-title, #wpforms-modal-checkbox-description").prop("checked",!1)),c("#wpforms-modal-backdrop, #wpforms-modal-wrap").css("display","none"),c(document.body).removeClass("modal-open")}c(document).on("click",".wpforms-insert-form-button",function(o){o.preventDefault(),c("#wpforms-modal-backdrop, #wpforms-modal-wrap").css("display","block"),c(document.body).addClass("modal-open")}),c(document).on("click","#wpforms-modal-close, #wpforms-modal-cancel a",function(o){o.preventDefault(),e()}),c(document).on("click","#wpforms-modal-submit",function(o){o.preventDefault(),o='[wpforms id="'+c("#wpforms-modal-select-form").val()+'"',c("#wpforms-modal-checkbox-title").is(":checked")&&(o+=' title="true"'),c("#wpforms-modal-checkbox-description").is(":checked")&&(o+=' description="true"'),o+="]",wp.media.editor.insert(o),e()})})})(jQuery);
|
||||
@@ -0,0 +1,194 @@
|
||||
/* global wpforms_admin, WPFormsAdmin */
|
||||
|
||||
/**
|
||||
* WPForms Admin Notifications.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var WPFormsAdminNotifications = window.WPFormsAdminNotifications || ( function( document, window, $ ) {
|
||||
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var el = {
|
||||
|
||||
$notifications: $( '#wpforms-notifications' ),
|
||||
$nextButton: $( '#wpforms-notifications .navigation .next' ),
|
||||
$prevButton: $( '#wpforms-notifications .navigation .prev' ),
|
||||
$adminBarCounter: $( '#wp-admin-bar-wpforms-menu .wpforms-menu-notification-counter' ),
|
||||
$adminBarMenuItem: $( '#wp-admin-bar-wpforms-notifications' ),
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*/
|
||||
init: function() {
|
||||
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*/
|
||||
ready: function() {
|
||||
|
||||
app.updateNavigation();
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Register JS events.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*/
|
||||
events: function() {
|
||||
|
||||
el.$notifications
|
||||
.on( 'click', '.dismiss', app.dismiss )
|
||||
.on( 'click', '.next', app.navNext )
|
||||
.on( 'click', '.prev', app.navPrev );
|
||||
},
|
||||
|
||||
/**
|
||||
* Click on the Dismiss notification button.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param {object} event Event object.
|
||||
*/
|
||||
dismiss: function( event ) {
|
||||
|
||||
if ( el.$currentMessage.length === 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update counter.
|
||||
var count = parseInt( el.$adminBarCounter.text(), 10 );
|
||||
if ( count > 1 ) {
|
||||
--count;
|
||||
el.$adminBarCounter.html( count );
|
||||
} else {
|
||||
el.$adminBarCounter.remove();
|
||||
el.$adminBarMenuItem.remove();
|
||||
}
|
||||
|
||||
// Remove notification.
|
||||
var $nextMessage = el.$nextMessage.length < 1 ? el.$prevMessage : el.$nextMessage,
|
||||
messageId = el.$currentMessage.data( 'message-id' );
|
||||
|
||||
if ( $nextMessage.length === 0 ) {
|
||||
el.$notifications.remove();
|
||||
} else {
|
||||
el.$currentMessage.remove();
|
||||
$nextMessage.addClass( 'current' );
|
||||
app.updateNavigation();
|
||||
}
|
||||
|
||||
// AJAX call - update option.
|
||||
var data = {
|
||||
action: 'wpforms_notification_dismiss',
|
||||
nonce: wpforms_admin.nonce,
|
||||
id: messageId,
|
||||
};
|
||||
|
||||
$.post( wpforms_admin.ajax_url, data, function( res ) {
|
||||
|
||||
if ( ! res.success ) {
|
||||
WPFormsAdmin.debug( res );
|
||||
}
|
||||
} ).fail( function( xhr, textStatus, e ) {
|
||||
|
||||
WPFormsAdmin.debug( xhr.responseText );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Click on the Next notification button.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param {object} event Event object.
|
||||
*/
|
||||
navNext: function( event ) {
|
||||
|
||||
if ( el.$nextButton.hasClass( 'disabled' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
el.$currentMessage.removeClass( 'current' );
|
||||
el.$nextMessage.addClass( 'current' );
|
||||
|
||||
app.updateNavigation();
|
||||
},
|
||||
|
||||
/**
|
||||
* Click on the Previous notification button.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param {object} event Event object.
|
||||
*/
|
||||
navPrev: function( event ) {
|
||||
|
||||
if ( el.$prevButton.hasClass( 'disabled' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
el.$currentMessage.removeClass( 'current' );
|
||||
el.$prevMessage.addClass( 'current' );
|
||||
|
||||
app.updateNavigation();
|
||||
},
|
||||
|
||||
/**
|
||||
* Update navigation buttons.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*/
|
||||
updateNavigation: function() {
|
||||
|
||||
el.$currentMessage = el.$notifications.find( '.wpforms-notifications-message.current' );
|
||||
el.$nextMessage = el.$currentMessage.next( '.wpforms-notifications-message' );
|
||||
el.$prevMessage = el.$currentMessage.prev( '.wpforms-notifications-message' );
|
||||
|
||||
if ( el.$nextMessage.length === 0 ) {
|
||||
el.$nextButton.addClass( 'disabled' );
|
||||
} else {
|
||||
el.$nextButton.removeClass( 'disabled' );
|
||||
}
|
||||
|
||||
if ( el.$prevMessage.length === 0 ) {
|
||||
el.$prevButton.addClass( 'disabled' );
|
||||
} else {
|
||||
el.$prevButton.removeClass( 'disabled' );
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return app;
|
||||
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPFormsAdminNotifications.init();
|
||||
+1
@@ -0,0 +1 @@
|
||||
var WPFormsAdminNotifications=window.WPFormsAdminNotifications||(t=>{var a={$notifications:t("#wpforms-notifications"),$nextButton:t("#wpforms-notifications .navigation .next"),$prevButton:t("#wpforms-notifications .navigation .prev"),$adminBarCounter:t("#wp-admin-bar-wpforms-menu .wpforms-menu-notification-counter"),$adminBarMenuItem:t("#wp-admin-bar-wpforms-notifications")},i={init:function(){t(i.ready)},ready:function(){i.updateNavigation(),i.events()},events:function(){a.$notifications.on("click",".dismiss",i.dismiss).on("click",".next",i.navNext).on("click",".prev",i.navPrev)},dismiss:function(e){var n,s;0!==a.$currentMessage.length&&(1<(s=parseInt(a.$adminBarCounter.text(),10))?a.$adminBarCounter.html(--s):(a.$adminBarCounter.remove(),a.$adminBarMenuItem.remove()),s=a.$nextMessage.length<1?a.$prevMessage:a.$nextMessage,n=a.$currentMessage.data("message-id"),0===s.length?a.$notifications.remove():(a.$currentMessage.remove(),s.addClass("current"),i.updateNavigation()),s={action:"wpforms_notification_dismiss",nonce:wpforms_admin.nonce,id:n},t.post(wpforms_admin.ajax_url,s,function(e){e.success||WPFormsAdmin.debug(e)}).fail(function(e,n,s){WPFormsAdmin.debug(e.responseText)}))},navNext:function(e){a.$nextButton.hasClass("disabled")||(a.$currentMessage.removeClass("current"),a.$nextMessage.addClass("current"),i.updateNavigation())},navPrev:function(e){a.$prevButton.hasClass("disabled")||(a.$currentMessage.removeClass("current"),a.$prevMessage.addClass("current"),i.updateNavigation())},updateNavigation:function(){a.$currentMessage=a.$notifications.find(".wpforms-notifications-message.current"),a.$nextMessage=a.$currentMessage.next(".wpforms-notifications-message"),a.$prevMessage=a.$currentMessage.prev(".wpforms-notifications-message"),0===a.$nextMessage.length?a.$nextButton.addClass("disabled"):a.$nextButton.removeClass("disabled"),0===a.$prevMessage.length?a.$prevButton.addClass("disabled"):a.$prevButton.removeClass("disabled")}};return i})((document,window,jQuery));WPFormsAdminNotifications.init();
|
||||
+2643
File diff suppressed because it is too large
Load Diff
+1
File diff suppressed because one or more lines are too long
+594
@@ -0,0 +1,594 @@
|
||||
/* global wpforms_builder_providers, wpforms_builder, wpf, WPForms, WPFormsBuilder */
|
||||
|
||||
( function( $ ) {
|
||||
|
||||
var s;
|
||||
|
||||
var WPFormsProviders = {
|
||||
|
||||
settings: {
|
||||
spinner: '<i class="wpforms-loading-spinner wpforms-loading-inline"></i>',
|
||||
spinnerWhite: '<i class="wpforms-loading-spinner wpforms-loading-inline wpforms-loading-white"></i>',
|
||||
},
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
init: function() {
|
||||
|
||||
s = this.settings;
|
||||
|
||||
// Document ready.
|
||||
$( WPFormsProviders.ready );
|
||||
|
||||
WPFormsProviders.bindUIActions();
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.1.1
|
||||
*/
|
||||
ready: function() {
|
||||
|
||||
// Setup/cache some vars not available before.
|
||||
s.form = $( '#wpforms-builder-form' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Element bindings.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
bindUIActions: function() {
|
||||
|
||||
// Delete connection.
|
||||
$( document ).on( 'click', '.wpforms-provider-connection-delete', function( e ) {
|
||||
WPFormsProviders.connectionDelete( this, e );
|
||||
} );
|
||||
|
||||
// Add new connection.
|
||||
$( document ).on( 'click', '.wpforms-provider-connections-add', function( e ) {
|
||||
WPFormsProviders.connectionAdd( this, e );
|
||||
} );
|
||||
|
||||
// Add new provider account.
|
||||
$( document ).on( 'click', '.wpforms-provider-account-add button', function( e ) {
|
||||
WPFormsProviders.accountAdd( this, e );
|
||||
} );
|
||||
|
||||
// Select provider account.
|
||||
$( document ).on( 'change', '.wpforms-provider-accounts select', function( e ) {
|
||||
WPFormsProviders.accountSelect( this, e );
|
||||
} );
|
||||
|
||||
// Select account list.
|
||||
$( document ).on( 'change', '.wpforms-provider-lists select', function( e ) {
|
||||
WPFormsProviders.accountListSelect( this, e );
|
||||
} );
|
||||
|
||||
// BC: Constant Contact v2, Aweber v1 and Campaign Monitor don't have JS logic for updating select fields with form fields options.
|
||||
// That's why we have to refresh the form every time when change something in fields and visit the Marketing tab.
|
||||
$( document ).on( 'wpformsPanelSwitch', function( e, targetPanel ) {
|
||||
const legacyProviders = [ 'aweber', 'campaign-monitor', 'constant-contact' ];
|
||||
const hasConfiguredLegacyProvider = legacyProviders.some( ( legacyProvider ) => $( `.wpforms-panel-content-section-${ legacyProvider } .wpforms-provider-connection` ).length > 0 );
|
||||
|
||||
if ( hasConfiguredLegacyProvider ) {
|
||||
WPFormsProviders.providerPanelConfirm( targetPanel );
|
||||
}
|
||||
} );
|
||||
|
||||
// Alert users if they save a form and do not configure required
|
||||
// fields.
|
||||
$( document ).on( 'wpformsSaved', function( e, data ) {
|
||||
var providerAlerts = [];
|
||||
var $connectionBlocks = $( '#wpforms-panel-providers' ).find( '.wpforms-connection-block' );
|
||||
|
||||
if ( ! $connectionBlocks.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$connectionBlocks.each( function() {
|
||||
var requiredEmpty = false,
|
||||
providerName;
|
||||
$( this ).find( 'table span.required' ).each( function() {
|
||||
var $element = $( this ).parent().parent().find( 'select' );
|
||||
if ( $element.val() === '' ) {
|
||||
requiredEmpty = true;
|
||||
}
|
||||
} );
|
||||
if ( requiredEmpty ) {
|
||||
var $titleArea = $( this ).closest( '.wpforms-panel-content-section' ).find( '.wpforms-panel-content-section-title' ).clone();
|
||||
$titleArea.find( 'button' ).remove();
|
||||
providerName = $titleArea.text().trim();
|
||||
var msg = wpforms_builder.provider_required_flds;
|
||||
|
||||
if ( -1 < providerAlerts.indexOf( providerName ) ) {
|
||||
return;
|
||||
}
|
||||
$.alert( {
|
||||
title: wpforms_builder.heads_up,
|
||||
content: msg.replace( '{provider}', providerName ),
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_builder.ok,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
providerAlerts.push( providerName );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Delete provider connection
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
connectionDelete: function( el, e ) {
|
||||
e.preventDefault();
|
||||
|
||||
var $this = $( el );
|
||||
|
||||
$.confirm( {
|
||||
title: false,
|
||||
content: wpforms_builder_providers.confirm_connection,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_builder.ok,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action: function() {
|
||||
|
||||
const $section = $this.closest( '.wpforms-panel-content-section' );
|
||||
|
||||
$this.closest( '.wpforms-provider-connection' ).remove();
|
||||
|
||||
// Update sidebar icon near the provider.
|
||||
const provider = $this.closest( '.wpforms-provider-connection' ).data( 'provider' ),
|
||||
$sidebarItem = $( '.wpforms-panel-sidebar-section-' + provider );
|
||||
|
||||
$sidebarItem.find( '.fa-check-circle-o' ).toggleClass( 'wpforms-hidden', $( $section ).find( '.wpforms-provider-connection' ).length <= 0 );
|
||||
|
||||
if ( ! $section.find( '.wpforms-provider-connection' ).length ) {
|
||||
$section.find( '.wpforms-builder-provider-connections-default' ).removeClass( 'wpforms-hidden' );
|
||||
}
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_builder.cancel,
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Add new provider connection.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
connectionAdd: function( el, e ) {
|
||||
e.preventDefault();
|
||||
|
||||
var $this = $( el ),
|
||||
$connections = $this.parent().parent(),
|
||||
$container = $this.parent(),
|
||||
provider = $this.data( 'provider' ),
|
||||
defaultValue = WPFormsProviders.getDefaultConnectionName( provider ).trim(),
|
||||
type = $this.data( 'type' ),
|
||||
namePrompt = wpforms_builder_providers.prompt_connection,
|
||||
nameField = '<input ' + ( defaultValue === '' ? ' autofocus=""' : '' ) + ' type="text" id="provider-connection-name" placeholder="' + wpforms_builder_providers.prompt_placeholder + '" value="' + defaultValue + '">',
|
||||
nameError = '<p class="error">' + wpforms_builder_providers.error_name + '</p>',
|
||||
modalContent = namePrompt + nameField + nameError;
|
||||
|
||||
modalContent = modalContent.replace( /%type%/g, type );
|
||||
|
||||
$.confirm( {
|
||||
title: false,
|
||||
content: modalContent,
|
||||
icon: 'fa fa-info-circle',
|
||||
type: 'blue',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_builder.ok,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action: function() {
|
||||
var name = this.$content.find( 'input#provider-connection-name' ).val().trim();
|
||||
var error = this.$content.find( '.error' );
|
||||
if ( name === '' ) {
|
||||
error.show();
|
||||
return false;
|
||||
} else {
|
||||
|
||||
// Disable button.
|
||||
WPFormsProviders.inputToggle( $this, 'disable' );
|
||||
|
||||
// Fire AJAX.
|
||||
var data = {
|
||||
action : 'wpforms_provider_ajax_' + provider,
|
||||
provider: provider,
|
||||
task : 'new_connection',
|
||||
name : name,
|
||||
id : s.form.data( 'id' ),
|
||||
nonce : wpforms_builder.nonce,
|
||||
};
|
||||
WPFormsProviders.fireAJAX( $this, data, function( res ) {
|
||||
if ( res.success ) {
|
||||
$connections.find( '.wpforms-builder-provider-connections-default' ).addClass( 'wpforms-hidden' );
|
||||
$connections.find( '.wpforms-provider-connections' ).prepend( res.data.html );
|
||||
|
||||
// Process and load the accounts if they exist.
|
||||
var $connection = $connections.find( '.wpforms-provider-connection' ).first();
|
||||
if ( $connection.find( '.wpforms-provider-accounts option:selected' ) ) {
|
||||
$connection.find( '.wpforms-provider-accounts option' ).first().prop( 'selected', true );
|
||||
$connection.find( '.wpforms-provider-accounts select' ).trigger( 'change' );
|
||||
}
|
||||
} else {
|
||||
WPFormsProviders.errorDisplay( res.data.error, $container );
|
||||
}
|
||||
} );
|
||||
}
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_builder.cancel,
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Add and authorize provider account.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
accountAdd: function( el, e ) {
|
||||
e.preventDefault();
|
||||
|
||||
var $this = $( el ),
|
||||
provider = $this.data( 'provider' ),
|
||||
$connection = $this.closest( '.wpforms-provider-connection' ),
|
||||
$container = $this.parent(),
|
||||
$fields = $container.find( ':input' ),
|
||||
errors = WPFormsProviders.requiredCheck( $fields, $container );
|
||||
|
||||
// Disable button.
|
||||
WPFormsProviders.inputToggle( $this, 'disable' );
|
||||
|
||||
// Bail if we have any errors.
|
||||
if ( errors ) {
|
||||
$this.prop( 'disabled', false ).find( 'i' ).remove();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fire AJAX.
|
||||
var data = {
|
||||
action : 'wpforms_provider_ajax_' + provider,
|
||||
provider : provider,
|
||||
connection_id: $connection.data( 'connection_id' ),
|
||||
task : 'new_account',
|
||||
data : WPFormsProviders.fakeSerialize( $fields ),
|
||||
};
|
||||
WPFormsProviders.fireAJAX( $this, data, function( res ) {
|
||||
if ( res.success ) {
|
||||
$container.nextAll( '.wpforms-connection-block' ).remove();
|
||||
$container.nextAll( '.wpforms-conditional-block' ).remove();
|
||||
$container.after( res.data.html );
|
||||
$container.slideUp();
|
||||
$connection.find( '.wpforms-provider-accounts select' ).trigger( 'change' );
|
||||
} else {
|
||||
WPFormsProviders.errorDisplay( res.data.error, $container );
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Selecting a provider account
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
accountSelect: function( el, e ) {
|
||||
e.preventDefault();
|
||||
|
||||
var $this = $( el ),
|
||||
$connection = $this.closest( '.wpforms-provider-connection' ),
|
||||
$container = $this.parent(),
|
||||
provider = $connection.data( 'provider' );
|
||||
|
||||
// Disable select, show loading.
|
||||
WPFormsProviders.inputToggle( $this, 'disable' );
|
||||
|
||||
// Remove any blocks that might exist as we prep for new account.
|
||||
$container.nextAll( '.wpforms-connection-block' ).remove();
|
||||
$container.nextAll( '.wpforms-conditional-block' ).remove();
|
||||
|
||||
if ( ! $this.val() ) {
|
||||
|
||||
// User selected to option to add new account.
|
||||
$connection.find( '.wpforms-provider-account-add input' ).val( '' );
|
||||
$connection.find( '.wpforms-provider-account-add' ).slideDown();
|
||||
WPFormsProviders.inputToggle( $this, 'enable' );
|
||||
|
||||
} else {
|
||||
|
||||
$connection.find( '.wpforms-provider-account-add' ).slideUp();
|
||||
|
||||
// Fire AJAX.
|
||||
var data = {
|
||||
action : 'wpforms_provider_ajax_' + provider,
|
||||
provider : provider,
|
||||
connection_id: $connection.data( 'connection_id' ),
|
||||
task : 'select_account',
|
||||
account_id : $this.find( ':selected' ).val(),
|
||||
};
|
||||
WPFormsProviders.fireAJAX( $this, data, function( res ) {
|
||||
if ( res.success ) {
|
||||
$container.after( res.data.html );
|
||||
|
||||
// Process first list found.
|
||||
$connection.find( '.wpforms-provider-lists option' ).first().prop( 'selected', true );
|
||||
$connection.find( '.wpforms-provider-lists select' ).trigger( 'change' );
|
||||
} else {
|
||||
WPFormsProviders.errorDisplay( res.data.error, $container );
|
||||
}
|
||||
} );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Selecting a provider account list.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
accountListSelect: function( el, e ) {
|
||||
e.preventDefault();
|
||||
|
||||
var $this = $( el ),
|
||||
$connection = $this.closest( '.wpforms-provider-connection' ),
|
||||
$container = $this.parent(),
|
||||
provider = $connection.data( 'provider' );
|
||||
|
||||
// Disable select, show loading.
|
||||
WPFormsProviders.inputToggle( $this, 'disable' );
|
||||
|
||||
// Remove any blocks that might exist as we prep for new account.
|
||||
$container.nextAll( '.wpforms-connection-block' ).remove();
|
||||
$container.nextAll( '.wpforms-conditional-block' ).remove();
|
||||
|
||||
var data = {
|
||||
action : 'wpforms_provider_ajax_' + provider,
|
||||
provider : provider,
|
||||
connection_id: $connection.data( 'connection_id' ),
|
||||
task : 'select_list',
|
||||
account_id : $connection.find( '.wpforms-provider-accounts option:selected' ).val(),
|
||||
list_id : $this.find( ':selected' ).val(),
|
||||
form_id : s.form.data( 'id' ),
|
||||
};
|
||||
|
||||
WPFormsProviders.fireAJAX( $this, data, function( res ) {
|
||||
if ( res.success ) {
|
||||
$container.after( res.data.html );
|
||||
|
||||
// Re-init tooltips for new fields.
|
||||
wpf.initTooltips();
|
||||
} else {
|
||||
WPFormsProviders.errorDisplay( res.data.error, $container );
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Confirm form save before loading Provider panel.
|
||||
* If confirmed, save and reload panel.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
providerPanelConfirm: function( targetPanel ) {
|
||||
|
||||
wpforms_panel_switch = true;
|
||||
if ( targetPanel === 'providers' && ! s.form.data( 'revision' ) ) {
|
||||
if ( ! WPFormsBuilder.formIsSaved() ) {
|
||||
wpforms_panel_switch = false;
|
||||
$.confirm( {
|
||||
title: false,
|
||||
content: wpforms_builder_providers.confirm_save,
|
||||
icon: 'fa fa-info-circle',
|
||||
type: 'blue',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_builder.ok,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action: function() {
|
||||
$( '#wpforms-save' ).trigger( 'click' );
|
||||
$( document ).on( 'wpformsSaved', function() {
|
||||
let wpforms_builder_provider_url = wpforms_builder_providers.url;
|
||||
const $section = $( `#wpforms-panel-${ targetPanel } .wpforms-panel-sidebar-section.active` );
|
||||
const section = $section.length && $section.data( 'section' ) !== 'default' ? $section.data( 'section' ) : null;
|
||||
|
||||
// Adding an active section parameter.
|
||||
if ( section ) {
|
||||
wpforms_builder_provider_url += `§ion=${ section }`;
|
||||
}
|
||||
|
||||
window.location.href = wpforms_builder_provider_url;
|
||||
} );
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_builder.cancel,
|
||||
},
|
||||
},
|
||||
} );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------//
|
||||
// Helper functions.
|
||||
//--------------------------------------------------------------------//
|
||||
|
||||
/**
|
||||
* Fire AJAX call.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
fireAJAX: function( el, d, success ) {
|
||||
var $this = $( el );
|
||||
var data = {
|
||||
id : $( '#wpforms-builder-form' ).data( 'id' ),
|
||||
nonce : wpforms_builder.nonce,
|
||||
};
|
||||
|
||||
$.extend( data, d );
|
||||
$.post( wpforms_builder.ajax_url, data, function( res ) {
|
||||
success( res );
|
||||
WPFormsProviders.inputToggle( $this, 'enable' );
|
||||
} ).fail( function( xhr, textStatus, e ) {
|
||||
console.log( xhr.responseText );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle input with loading indicator.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
inputToggle: function( el, status ) {
|
||||
var $this = $( el );
|
||||
if ( status === 'enable' ) {
|
||||
if ( $this.is( 'select' ) ) {
|
||||
$this.prop( 'disabled', false ).next( 'i' ).remove();
|
||||
} else {
|
||||
$this.prop( 'disabled', false ).find( 'i' ).remove();
|
||||
}
|
||||
} else if ( status === 'disable' ) {
|
||||
if ( $this.is( 'select' ) ) {
|
||||
$this.prop( 'disabled', true ).after( s.spinner );
|
||||
} else {
|
||||
$this.prop( 'disabled', true ).prepend( s.spinnerWhite );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Display error.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
errorDisplay: function( msg, location ) {
|
||||
location.find( '.wpforms-error-msg' ).remove();
|
||||
location.prepend( '<p class="wpforms-alert-danger wpforms-alert wpforms-error-msg">' + msg + '</p>' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Check for required fields.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
requiredCheck: function( fields, location ) {
|
||||
var error = false;
|
||||
|
||||
// Remove any previous errors.
|
||||
location.find( '.wpforms-alert-required' ).remove();
|
||||
|
||||
// Loop through input fields and check for values.
|
||||
fields.each( function( index, el ) {
|
||||
if ( $( el ).hasClass( 'wpforms-required' ) && $( el ).val().length === 0 ) {
|
||||
$( el ).addClass( 'wpforms-error' );
|
||||
error = true;
|
||||
} else {
|
||||
$( el ).removeClass( 'wpforms-error' );
|
||||
}
|
||||
} );
|
||||
if ( error ) {
|
||||
location.prepend( '<p class="wpforms-alert-danger wpforms-alert wpforms-alert-required">' + wpforms_builder_providers.required_field + '</p>' );
|
||||
}
|
||||
return error;
|
||||
},
|
||||
|
||||
/**
|
||||
* Pseudo serializing. Fake it until you make it.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
fakeSerialize: function( els ) {
|
||||
var fields = els.clone();
|
||||
|
||||
fields.each( function( index, el ) {
|
||||
if ( $( el ).data( 'name' ) ) {
|
||||
$( el ).attr( 'name', $( el ).data( 'name' ) );
|
||||
}
|
||||
} );
|
||||
return fields.serialize();
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the default name for a new connection.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {string} provider Current provider slug.
|
||||
*
|
||||
* @return {string} Returns the default name for a new connection.
|
||||
*/
|
||||
getDefaultConnectionName( provider ) {
|
||||
const providerName = $( `#${ provider }-provider` ).data( 'provider-name' );
|
||||
const numberOfConnections = WPFormsProviders.getCountConnectionsOf( provider );
|
||||
const defaultName = `${ providerName } ${ wpforms_builder.connection_label }`;
|
||||
|
||||
return numberOfConnections < 1 ? defaultName : '';
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the number of connections for the provider.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {string} provider Current provider slug.
|
||||
*
|
||||
* @return {number} Returns the number of connections for the provider.
|
||||
*/
|
||||
getCountConnectionsOf( provider ) {
|
||||
return $( `#${ provider }-provider .wpforms-provider-connection` ).length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a provider JS object.
|
||||
*
|
||||
* @since 1.9.3
|
||||
* @deprecated 1.9.5 Not used anymore.
|
||||
*
|
||||
* @param {string} provider Provider name.
|
||||
*
|
||||
* @return {Object|null} Return provider object or null.
|
||||
*/
|
||||
getProviderClass( provider ) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn( 'WARNING! Function "WPFormsProviders.getProviderClass()" has been deprecated!' );
|
||||
|
||||
const upperProviderPart = ( providerPart ) => (
|
||||
providerPart.charAt( 0 ).toUpperCase() + providerPart.slice( 1 )
|
||||
);
|
||||
|
||||
const getClassName = provider.split( '-' ).map( upperProviderPart ).join( '' );
|
||||
|
||||
if ( typeof WPForms?.Admin?.Builder?.Providers?.[ getClassName ] === 'undefined' ) {
|
||||
return null;
|
||||
}
|
||||
return WPForms.Admin.Builder.Providers[ getClassName ];
|
||||
},
|
||||
};
|
||||
|
||||
WPFormsProviders.init();
|
||||
} )( jQuery );
|
||||
Vendored
Executable
+1
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
+25
File diff suppressed because one or more lines are too long
+81
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Chocolate choices' functionality.
|
||||
*
|
||||
* @since 1.9.6.1
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const WPFormsChocolateChoices = {
|
||||
/**
|
||||
* Initializes the chocolate choices component.
|
||||
*
|
||||
* @since 1.9.6.1
|
||||
*
|
||||
* @param {Object} $grid The grid container for the choices.
|
||||
* @param {Object} options Object with name and choices properties.
|
||||
* @param {string} options.name The name attribute for the checkbox inputs.
|
||||
* @param {Array} options.choices Array of choice objects with label and value properties.
|
||||
* @param {Array} options.selected Array of selected choice values.
|
||||
*/
|
||||
init( $grid, options ) {
|
||||
const selected = options.selected?.map?.( String ) ?? [];
|
||||
const $ = jQuery;
|
||||
/**
|
||||
* Generate a random ID string.
|
||||
* The ID is based on current timestamp and converted to a base-16 string.
|
||||
*
|
||||
* @since 1.9.6.1
|
||||
*
|
||||
* @return {string} A hexadecimal string representation of the current timestamp.
|
||||
*/
|
||||
const getRandomId = () => new Date().getTime().toString( 16 );
|
||||
|
||||
/**
|
||||
* Creates a single choice item.
|
||||
*
|
||||
* @since 1.9.6.1
|
||||
*
|
||||
* @param {Object|string|number} itemData The choice data object with label and value.
|
||||
* @param {number} index The index of the choice item.
|
||||
*
|
||||
* @return {jQuery} The created choice item element.
|
||||
*/
|
||||
const createChoiceItem = ( itemData, index ) => {
|
||||
const id = `choice-${ index }-${ getRandomId() }`;
|
||||
const itemValue = String( typeof itemData === 'object' ? itemData.value : itemData );
|
||||
|
||||
// Create the container div.
|
||||
const $itemDiv = $( '<div>', {
|
||||
class: 'choice-item',
|
||||
} );
|
||||
|
||||
// Create the checkbox input.
|
||||
const $checkbox = $( '<input>', {
|
||||
type: 'checkbox',
|
||||
id,
|
||||
value: itemValue,
|
||||
checked: selected.includes( itemValue ),
|
||||
name: options.name.replace( '{index}', index ),
|
||||
} );
|
||||
|
||||
// Create the label.
|
||||
const $label = $( '<label>', { for: id } );
|
||||
$label.text( itemData.label ?? itemData );
|
||||
|
||||
// Append elements.
|
||||
$itemDiv.append( $checkbox, $label );
|
||||
|
||||
return $itemDiv;
|
||||
};
|
||||
|
||||
// Clear existing content.
|
||||
$grid.html( '' );
|
||||
const choices = [];
|
||||
|
||||
// Populate the grid with items.
|
||||
$.each( options.choices, function( index, choiceData ) {
|
||||
choices.push( createChoiceItem( choiceData, index ) );
|
||||
} );
|
||||
|
||||
$grid.append( choices );
|
||||
},
|
||||
};
|
||||
Vendored
Executable
+1
@@ -0,0 +1 @@
|
||||
let WPFormsChocolateChoices={init(e,n){let l=n.selected?.map?.(String)??[],o=jQuery,c=(e,t)=>{var c=`choice-${t}-`+(new Date).getTime().toString(16),i=String("object"==typeof e?e.value:e),a=o("<div>",{class:"choice-item"}),i=o("<input>",{type:"checkbox",id:c,value:i,checked:l.includes(i),name:n.name.replace("{index}",t)}),t=o("<label>",{for:c});return t.text(e.label??e),a.append(i,t),a},i=(e.html(""),[]);o.each(n.choices,function(e,t){i.push(c(t,e))}),e.append(i)}};
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Checkbox selection functionality.
|
||||
*
|
||||
* @since 1.9.6.1
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const WPFormsChoicesList = {
|
||||
/**
|
||||
* Creates and returns a checkbox selection manager.
|
||||
*
|
||||
* @since 1.9.6.1
|
||||
*
|
||||
* @param {jQuery} $container The container element with checkboxes.
|
||||
*/
|
||||
init( $container ) {
|
||||
if ( $container.data( 'choices-list-initialized' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$container.data( 'choices-list-initialized', true );
|
||||
|
||||
// Private variables to store state.
|
||||
const $selectAllCheckbox = $container.find( 'input[value="select-all"]' );
|
||||
const $itemCheckboxes = $container.find( '.item-checkbox' );
|
||||
|
||||
/**
|
||||
* Checks if the container has the necessary elements to initialize.
|
||||
*
|
||||
* @since 1.9.6.1
|
||||
*
|
||||
* @param {Object} $rootContainer The root container element to query for required elements.
|
||||
*
|
||||
* @return {boolean} True if the root container contains specific elements required for initialization, otherwise false.
|
||||
*/
|
||||
const canInitialize = ( $rootContainer ) => {
|
||||
const hasSelectAll = $rootContainer.find( 'input[value="select-all"]' ).length > 0;
|
||||
const hasItemCheckboxes = $rootContainer.find( '.item-checkbox' ).length > 0;
|
||||
return hasSelectAll && hasItemCheckboxes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the state of the "Select All" checkbox based on the current
|
||||
* state of individual item checkboxes. Determines whether all, none,
|
||||
* or some items are selected and updates the "Select All" checkbox.
|
||||
*
|
||||
* @since 1.9.6.1
|
||||
*/
|
||||
const updateSelectAllState = () => {
|
||||
this.updateSelectAllState( $container );
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the change event for the "Select All" checkbox. Updates the state
|
||||
* of individual item checkboxes and clears the indeterminate state of the
|
||||
* "Select All" checkbox.
|
||||
*
|
||||
* @since 1.9.6.1
|
||||
*
|
||||
* @param {Event} event The event object associated with the change event triggered on the "Select All" checkbox.
|
||||
*/
|
||||
const handleSelectAllChange = ( event ) => {
|
||||
const isChecked = jQuery( event.target ).prop( 'checked' );
|
||||
|
||||
// Update all item checkboxes.
|
||||
$itemCheckboxes.prop( 'checked', isChecked );
|
||||
|
||||
// Clear indeterminate state.
|
||||
$selectAllCheckbox.prop( 'indeterminate', false );
|
||||
};
|
||||
|
||||
/**
|
||||
* Binds event listeners to the "select all" checkbox and item checkboxes.
|
||||
*
|
||||
* @since 1.9.6.1
|
||||
*/
|
||||
const bindEvents = () => {
|
||||
// Add event listener to "select all" checkbox.
|
||||
$selectAllCheckbox.on( 'change', handleSelectAllChange );
|
||||
|
||||
// Add event listeners to item checkboxes.
|
||||
$itemCheckboxes.on( 'change', updateSelectAllState );
|
||||
};
|
||||
|
||||
// Return early if required elements aren't found.
|
||||
if ( ! canInitialize( $container ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize event bindings.
|
||||
bindEvents();
|
||||
|
||||
// Initialize the state.
|
||||
updateSelectAllState();
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the select all checkbox state based on the current checked state of item checkboxes.
|
||||
* This method can be called from outside the class to refresh the state after DOM changes.
|
||||
*
|
||||
* @since 1.9.6.1
|
||||
*
|
||||
* @param {jQuery} $container The container element with checkboxes.
|
||||
*/
|
||||
updateSelectAllState( $container ) {
|
||||
const $selectAllCheckbox = $container.find( 'input[value="select-all"]' );
|
||||
const $itemCheckboxes = $container.find( '.item-checkbox' );
|
||||
|
||||
const totalItems = $itemCheckboxes.length;
|
||||
const checkedItems = $itemCheckboxes.filter( ':checked' ).length;
|
||||
|
||||
if ( checkedItems === 0 ) {
|
||||
// None checked.
|
||||
$selectAllCheckbox.prop( {
|
||||
checked: false,
|
||||
indeterminate: false,
|
||||
} );
|
||||
} else if ( checkedItems === totalItems ) {
|
||||
// All checked.
|
||||
$selectAllCheckbox.prop( {
|
||||
checked: true,
|
||||
indeterminate: false,
|
||||
} );
|
||||
} else {
|
||||
// Some checked.
|
||||
$selectAllCheckbox.prop( {
|
||||
checked: false,
|
||||
indeterminate: true,
|
||||
} );
|
||||
}
|
||||
},
|
||||
};
|
||||
+1
@@ -0,0 +1 @@
|
||||
let WPFormsChoicesList={init(l){if(!l.data("choices-list-initialized")){l.data("choices-list-initialized",!0);let t=l.find('input[value="select-all"]'),i=l.find(".item-checkbox");let e=()=>{this.updateSelectAllState(l)},c=e=>{e=jQuery(e.target).prop("checked");i.prop("checked",e),t.prop("indeterminate",!1)};var n,a;a=0<(n=l).find('input[value="select-all"]').length,n=0<n.find(".item-checkbox").length,a&&n&&(t.on("change",c),i.on("change",e),e())}},updateSelectAllState(e){var t=e.find('input[value="select-all"]'),e=e.find(".item-checkbox"),i=e.length,e=e.filter(":checked").length;0===e?t.prop({checked:!1,indeterminate:!1}):e===i?t.prop({checked:!0,indeterminate:!1}):t.prop({checked:!1,indeterminate:!0})}};
|
||||
@@ -0,0 +1,714 @@
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
/* global wpf, WPFormsBuilder, WPSplash */
|
||||
|
||||
/**
|
||||
* Context menu module.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
|
||||
var WPForms = window.WPForms || {}; // eslint-disable-line no-var
|
||||
|
||||
WPForms.Admin = WPForms.Admin || {};
|
||||
WPForms.Admin.Builder = WPForms.Admin.Builder || {};
|
||||
|
||||
WPForms.Admin.Builder.ContextMenu = WPForms.Admin.Builder.ContextMenu || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const el = {};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* CSS selectors.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
selectors: {
|
||||
contextMenu: '.wpforms-context-menu',
|
||||
mainContextMenuContainer: '#wpforms-context-menu-container',
|
||||
mainContextMenu: '#wpforms-context-menu',
|
||||
fieldContextMenu: '#wpforms-field-context-menu',
|
||||
contextMenuItem: '.wpforms-context-menu:not(.wpforms-context-menu-dropdown) .wpforms-context-menu-list-item',
|
||||
contextMenuSelectiveItem: '.wpforms-context-menu-list-item-selective',
|
||||
contextMenuDivider: '.wpforms-context-menu .wpforms-context-menu-list-divider',
|
||||
builder: '#wpforms-builder',
|
||||
sidebarToggle: '.wpforms-panels .wpforms-panel-sidebar-content .wpforms-panel-sidebar-toggle',
|
||||
},
|
||||
|
||||
/**
|
||||
* Start the engine. DOM is not ready yet, use only to init something.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* DOM is fully loaded.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
ready() {
|
||||
app.setup();
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup. Prepare some variables.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
setup() {
|
||||
// Cache DOM elements.
|
||||
el.$document = $( document );
|
||||
el.$contextMenu = $( app.selectors.contextMenu );
|
||||
el.$mainContextMenuContainer = $( app.selectors.mainContextMenuContainer );
|
||||
el.$mainContextMenu = $( app.selectors.mainContextMenu );
|
||||
el.$fieldContextMenu = $( app.selectors.fieldContextMenu );
|
||||
el.$contextMenuItem = $( app.selectors.contextMenuItem );
|
||||
el.$contextMenuSelectiveItem = $( app.selectors.contextMenuSelectiveItem );
|
||||
el.$contextMenuDivider = $( app.selectors.contextMenuDivider );
|
||||
el.$builder = $( app.selectors.builder );
|
||||
el.$sidebarToggle = $( app.selectors.sidebarToggle );
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
events() {
|
||||
// Display a main menu on click on the icon in the toolbar.
|
||||
el.$mainContextMenuContainer.on( 'click', ( event ) => {
|
||||
event.preventDefault();
|
||||
|
||||
el.$mainContextMenu.fadeToggle( 150, () => {
|
||||
el.$mainContextMenuContainer.toggleClass( 'wpforms-context-menu-active' );
|
||||
} );
|
||||
} );
|
||||
|
||||
// Handle clicks on the main menu items.
|
||||
el.$mainContextMenu.on( 'click', '.wpforms-context-menu-list-item', app.mainMenuItemClickAction );
|
||||
|
||||
// Hide the main menu if it's visible when clicking outside it.
|
||||
el.$builder.on( 'click contextmenu', app.hideMainContextMenu );
|
||||
|
||||
// Display a context menu on right-click on the form field in the preview area.
|
||||
el.$document.on( 'contextmenu', app.rightClickContextMenuHandler );
|
||||
|
||||
el.$document.on( 'click', app.hideMenuOnClick );
|
||||
el.$builder.on( 'wpformsFieldTabToggle', app.hideMenuOnClick );
|
||||
},
|
||||
|
||||
/**
|
||||
* Right-click context menu handler.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*
|
||||
* @param {KeyboardEvent} e Event object.
|
||||
*/
|
||||
rightClickContextMenuHandler( e ) {
|
||||
const $field = $( e.target ).closest( '.wpforms-field' );
|
||||
const $panel = $field.closest( '#wpforms-panel-fields' );
|
||||
|
||||
if ( ! $panel.length || ! $field.length || $( e.target ).closest( app.selectors.contextMenu ).length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
app.hideMenu();
|
||||
|
||||
if ( e.ctrlKey ) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
setTimeout( function() {
|
||||
app.checkMenuItemsVisibility( $field );
|
||||
app.checkDividerVisibility();
|
||||
app.menuPositioning( e );
|
||||
app.menuItemClickAction( $field );
|
||||
app.checkSelectiveMenuItemsState( $field );
|
||||
}, 150 );
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide the main context menu when clicking outside it.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*
|
||||
* @param {Event} event Event object.
|
||||
*/
|
||||
hideMainContextMenu( event ) {
|
||||
if ( el.$mainContextMenu.is( ':hidden' ) || $( event.target ).closest( app.selectors.mainContextMenuContainer ).length > 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
el.$mainContextMenu.fadeOut( 150, () => {
|
||||
el.$mainContextMenuContainer.removeClass( 'wpforms-context-menu-active' );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Main menu item click action.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
mainMenuItemClickAction() {
|
||||
const $item = $( this );
|
||||
const action = $item.data( 'action' );
|
||||
const actionUrl = $item.data( 'action-url' ) ?? '';
|
||||
|
||||
const actionHandlers = {
|
||||
'duplicate-form': () => app.handleUrlAction( actionUrl, false, true ),
|
||||
'save-as-template': () => app.handleUrlAction( actionUrl, false, true ),
|
||||
'duplicate-template': () => app.handleUrlAction( actionUrl, false, true ),
|
||||
'view-entries': () => app.handleUrlAction( actionUrl, true ),
|
||||
'view-payments': () => app.handleUrlAction( actionUrl, true ),
|
||||
'keyboard-shortcuts': WPFormsBuilder.openKeyboardShortcutsModal,
|
||||
'whats-new': app.handleWhatsNewAction,
|
||||
};
|
||||
|
||||
const handler = actionHandlers[ action ];
|
||||
|
||||
if ( handler ) {
|
||||
handler();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Menu item click action.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} $field Field object.
|
||||
*/
|
||||
menuItemClickAction( $field ) {
|
||||
const fieldId = $field.data( 'field-id' );
|
||||
|
||||
el.$contextMenuItem.off( 'click' ).on( 'click', function() {
|
||||
const $item = $( this );
|
||||
|
||||
if ( $item.hasClass( 'wpforms-context-menu-list-item-has-child' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const action = $item.data( 'action' );
|
||||
const actionHandlers = {
|
||||
edit: () => app.handleEditAction( $field, fieldId ),
|
||||
duplicate: () => app.handleDuplicateAction( $field ),
|
||||
delete: () => app.handleDeleteAction( $field ),
|
||||
required: () => app.handleRequiredAction( $item, fieldId ),
|
||||
label: () => app.handleLabelAction( $item, fieldId ),
|
||||
'smart-logic': () => app.handleSmartLogicAction( $field, fieldId ),
|
||||
'field-size': () => app.handleSizeAction( $item, fieldId ),
|
||||
};
|
||||
|
||||
const handler = actionHandlers[ action ];
|
||||
|
||||
if ( handler ) {
|
||||
handler();
|
||||
}
|
||||
|
||||
app.hideMenu();
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle edit action.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} $field Field object.
|
||||
* @param {string} fieldId Field ID.
|
||||
*/
|
||||
handleEditAction( $field, fieldId ) {
|
||||
$field.trigger( 'click' );
|
||||
|
||||
// This is needed to make sure the sidebar is open when the "Edit" button is clicked.
|
||||
app.maybeOpenSidebar();
|
||||
|
||||
$( `#wpforms-field-option-basic-${ fieldId } .wpforms-field-option-group-toggle` ).trigger( 'click' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle duplicate action.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} $field Field object.
|
||||
*/
|
||||
handleDuplicateAction( $field ) {
|
||||
$field.find( '.wpforms-field-duplicate' ).first().trigger( 'click' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle delete action.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} $field Field object.
|
||||
*/
|
||||
handleDeleteAction( $field ) {
|
||||
$field.find( '.wpforms-field-delete' ).first().trigger( 'click' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle required action.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} $item Menu item object.
|
||||
* @param {string} fieldId Field ID.
|
||||
*/
|
||||
handleRequiredAction( $item, fieldId ) {
|
||||
$( `#wpforms-field-option-${ fieldId }-required` ).trigger( 'click' );
|
||||
const state = app.checkRequiredState( fieldId ) ? 'active' : 'inactive';
|
||||
app.toggleItemText( $item, state );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle label action.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} $item Menu item object.
|
||||
* @param {string} fieldId Field ID.
|
||||
*/
|
||||
handleLabelAction( $item, fieldId ) {
|
||||
$( `#wpforms-field-option-${ fieldId }-label_hide` ).trigger( 'click' );
|
||||
const state = app.checkLabelState( fieldId ) ? 'active' : 'inactive';
|
||||
app.toggleItemText( $item, state );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle smart logic action.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} $field Field object.
|
||||
* @param {string} fieldId Field ID.
|
||||
*/
|
||||
handleSmartLogicAction( $field, fieldId ) {
|
||||
// This is needed to make sure the sidebar is open when the "Edit Conditional Logic" button is clicked.
|
||||
app.maybeOpenSidebar();
|
||||
|
||||
$field.trigger( 'click' );
|
||||
$( `#wpforms-field-option-conditionals-${ fieldId } .wpforms-field-option-group-toggle` ).trigger( 'click' );
|
||||
$( `#wpforms-field-option-${ fieldId } .wpforms-field-option-group-conditionals .education-modal` ).trigger( 'click' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle size action.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} $item Menu item object.
|
||||
* @param {string} fieldId Field ID.
|
||||
*/
|
||||
handleSizeAction( $item, fieldId ) {
|
||||
const value = $item.data( 'value' );
|
||||
|
||||
$( `#wpforms-field-option-${ fieldId }-size` ).val( value ).trigger( 'change' );
|
||||
$item.addClass( 'wpforms-context-menu-list-item-active' ).siblings().removeClass( 'wpforms-context-menu-list-item-active' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle "What's New" action.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
handleWhatsNewAction() {
|
||||
const modal = $( '#tmpl-wpforms-splash-modal-content' );
|
||||
|
||||
if ( modal.length && typeof WPSplash !== 'undefined' ) {
|
||||
WPSplash.openModal();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle a simple URL action.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*
|
||||
* @param {string} actionUrl URL.
|
||||
* @param {boolean} newTab Whether to open the URL in a new tab.
|
||||
* @param {boolean} saveForm Whether to save the form before following the action URL.
|
||||
*/
|
||||
handleUrlAction( actionUrl, newTab = false, saveForm = false ) {
|
||||
if ( ! actionUrl ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The form does not need to be saved, open the URL.
|
||||
if ( ! saveForm ) {
|
||||
newTab ? window.open( actionUrl ) : window.location.assign( actionUrl ); // eslint-disable-line no-unused-expressions
|
||||
return;
|
||||
}
|
||||
|
||||
// The form was changed and must be saved before following the action URL.
|
||||
if ( ! WPFormsBuilder.formIsSaved() ) {
|
||||
el.$builder.on( 'wpformsSaved', () => {
|
||||
newTab ? window.open( actionUrl ) : window.location.assign( actionUrl ); // eslint-disable-line no-unused-expressions
|
||||
} );
|
||||
|
||||
WPFormsBuilder.formSave( false );
|
||||
return;
|
||||
}
|
||||
|
||||
// The form was not changed, open the URL.
|
||||
newTab ? window.open( actionUrl ) : window.location.assign( actionUrl ); // eslint-disable-line no-unused-expressions
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle item text.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} $item Menu item object.
|
||||
* @param {string} state State.
|
||||
*/
|
||||
toggleItemText( $item, state ) {
|
||||
const $text = $item.find( '.wpforms-context-menu-list-item-text' );
|
||||
const activeText = $text.data( 'active-text' );
|
||||
const inactiveText = $text.data( 'inactive-text' ) || $text.text();
|
||||
|
||||
if ( ! activeText ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$text.data( 'inactive-text', inactiveText );
|
||||
$text.text( state === 'active' ? activeText : inactiveText );
|
||||
},
|
||||
|
||||
/**
|
||||
* Check selective menu items state.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} $field Field object.
|
||||
*/
|
||||
checkSelectiveMenuItemsState( $field ) {
|
||||
const fieldId = $field.data( 'field-id' );
|
||||
|
||||
el.$contextMenuSelectiveItem.each( function() {
|
||||
const $item = $( this );
|
||||
const action = $item.data( 'action' );
|
||||
const value = $item.data( 'value' );
|
||||
|
||||
const shouldChangeStateHandlers = {
|
||||
required: () => app.checkRequiredState( fieldId ),
|
||||
label: () => app.checkLabelState( fieldId ),
|
||||
'field-size': () => app.checkFieldSizeState( fieldId, value ),
|
||||
};
|
||||
|
||||
const handler = shouldChangeStateHandlers[ action ];
|
||||
|
||||
if ( handler() ) {
|
||||
$item.addClass( 'wpforms-context-menu-list-item-active' );
|
||||
app.toggleItemText( $item, 'active' );
|
||||
} else {
|
||||
$item.removeClass( 'wpforms-context-menu-list-item-active' );
|
||||
app.toggleItemText( $item, 'inactive' );
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Check the required state.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} fieldId Field ID.
|
||||
*
|
||||
* @return {boolean} True if option checked.
|
||||
*/
|
||||
checkRequiredState( fieldId ) {
|
||||
return $( `#wpforms-field-option-${ fieldId }-required[type="checkbox"]` ).is( ':checked' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Check label state.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} fieldId Field ID.
|
||||
*
|
||||
* @return {boolean} True if option checked.
|
||||
*/
|
||||
checkLabelState( fieldId ) {
|
||||
return $( `#wpforms-field-option-${ fieldId }-label_hide[type="checkbox"]` ).is( ':checked' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Check field size state.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} fieldId Field ID.
|
||||
* @param {string} value Value.
|
||||
*
|
||||
* @return {boolean} True if value equals.
|
||||
*/
|
||||
checkFieldSizeState( fieldId, value ) {
|
||||
return $( `#wpforms-field-option-${ fieldId }-size` ).val() === value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Menu positioning.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
*/
|
||||
menuPositioning( e ) {
|
||||
const menuWidth = el.$fieldContextMenu.width();
|
||||
const menuHeight = el.$fieldContextMenu.height();
|
||||
const windowWidth = window.innerWidth;
|
||||
const windowHeight = window.innerHeight;
|
||||
|
||||
el.$fieldContextMenu.removeClass( 'wpforms-context-menu-selective-left' );
|
||||
|
||||
let topPosition = e.pageY;
|
||||
let leftPosition = e.pageX;
|
||||
|
||||
if ( e.pageY + menuHeight > windowHeight ) {
|
||||
topPosition = windowHeight - menuHeight - 15;
|
||||
}
|
||||
|
||||
if ( e.pageX + menuWidth > windowWidth ) {
|
||||
leftPosition = windowWidth - menuWidth - 15;
|
||||
el.$fieldContextMenu.addClass( 'wpforms-context-menu-selective-left' );
|
||||
}
|
||||
|
||||
el.$fieldContextMenu.css( {
|
||||
top: topPosition + 'px',
|
||||
left: leftPosition + 'px',
|
||||
} );
|
||||
|
||||
el.$fieldContextMenu.fadeIn( 150 );
|
||||
},
|
||||
|
||||
/**
|
||||
* Check menu items visibility.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} $field jQuery object.
|
||||
*/
|
||||
checkMenuItemsVisibility( $field ) {
|
||||
const fieldId = $field.data( 'field-id' );
|
||||
|
||||
const shouldHideHandlers = {
|
||||
edit: () => app.shouldHideEdit( $field ),
|
||||
duplicate: () => app.shouldHideDuplicate( $field ),
|
||||
delete: () => app.shouldHideDelete( $field ),
|
||||
required: () => app.shouldHideRequired( fieldId ),
|
||||
label: () => app.shouldHideLabel( fieldId ),
|
||||
'smart-logic': () => app.shouldHideSmartLogic( fieldId ),
|
||||
'field-size': () => app.shouldHideFieldSize( fieldId, $field ),
|
||||
};
|
||||
|
||||
el.$contextMenuItem.each( function() {
|
||||
const $item = $( this );
|
||||
const action = $item.data( 'action' );
|
||||
const handler = shouldHideHandlers[ action ];
|
||||
|
||||
if ( handler() ) {
|
||||
$item.hide();
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Check edit visibility.
|
||||
*
|
||||
* @since 1.8.7
|
||||
*
|
||||
* @param {Object} $field Field object.
|
||||
*
|
||||
* @return {boolean} True when should hide.
|
||||
*/
|
||||
shouldHideEdit( $field ) {
|
||||
return $field.hasClass( 'internal-information-not-editable' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Check duplicate visibility.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} $field Field object.
|
||||
*
|
||||
* @return {boolean} True when should hide.
|
||||
*/
|
||||
shouldHideDuplicate( $field ) {
|
||||
const $duplicate = $field.find( '.wpforms-field-duplicate' );
|
||||
|
||||
return $duplicate.length === 0 || $duplicate.css( 'display' ) === 'none';
|
||||
},
|
||||
|
||||
/**
|
||||
* Check delete visibility.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} $field Field object.
|
||||
*
|
||||
* @return {boolean} True when should hide.
|
||||
*/
|
||||
shouldHideDelete( $field ) {
|
||||
const $delete = $field.find( '.wpforms-field-delete' );
|
||||
|
||||
return $delete.length === 0 || $delete.css( 'display' ) === 'none';
|
||||
},
|
||||
|
||||
/**
|
||||
* Check the required visibility.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} fieldId Field ID.
|
||||
*
|
||||
* @return {boolean} True when should hide.
|
||||
*/
|
||||
shouldHideRequired( fieldId ) {
|
||||
return $( `#wpforms-field-option-${ fieldId }-required[type="checkbox"]` ).length === 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check label visibility.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} fieldId Field ID.
|
||||
*
|
||||
* @return {boolean} True when should hide.
|
||||
*/
|
||||
shouldHideLabel( fieldId ) {
|
||||
const $label = $( `#wpforms-field-option-${ fieldId }-label_hide[type="checkbox"]` );
|
||||
|
||||
return $label.length === 0 || $label.parents( '.wpforms-field-option-row' ).hasClass( 'wpforms-disabled' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Check field size visibility.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} fieldId Field ID.
|
||||
* @param {Object} $field Field object.
|
||||
*
|
||||
* @return {boolean} True when should hide.
|
||||
*/
|
||||
shouldHideFieldSize( fieldId, $field ) {
|
||||
const isFieldInColumn = $field.closest( '.wpforms-layout-column' ).length > 0;
|
||||
const isRepeaterField = $field.closest( '.wpforms-field-repeater' ).length > 0;
|
||||
const $size = $( `#wpforms-field-option-${ fieldId }-size` );
|
||||
|
||||
return $size.length === 0 || isFieldInColumn || isRepeaterField || $size.parent().hasClass( 'wpforms-hidden' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Check smart logic visibility.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} fieldId Field ID.
|
||||
*
|
||||
* @return {boolean} True when should hide.
|
||||
*/
|
||||
shouldHideSmartLogic( fieldId ) {
|
||||
return $( `#wpforms-field-option-conditionals-${ fieldId }` ).length === 0 && $( `#wpforms-field-option-${ fieldId } .wpforms-field-option-group-conditionals .education-modal` ).length === 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check divider visibility.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
checkDividerVisibility() {
|
||||
el.$contextMenuDivider.each( function() {
|
||||
const $divider = $( this );
|
||||
const visibility = $divider.data( 'visibility' ) ?? '';
|
||||
|
||||
let shouldHide = true;
|
||||
|
||||
visibility.split( ',' ).forEach( function( item ) {
|
||||
if ( $( '.wpforms-context-menu-list-item[data-action="' + item.trim() + '"]' ).css( 'display' ) !== 'none' ) {
|
||||
shouldHide = false;
|
||||
}
|
||||
} );
|
||||
|
||||
if ( shouldHide ) {
|
||||
$divider.hide();
|
||||
} else {
|
||||
$divider.show();
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide menu.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
hideMenu() {
|
||||
el.$fieldContextMenu.fadeOut( 150 );
|
||||
setTimeout( function() {
|
||||
el.$contextMenuItem.show();
|
||||
}, 150 );
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide menu on click.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
*/
|
||||
hideMenuOnClick( e ) {
|
||||
if ( $( e.target ).closest( app.selectors.contextMenu ).length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
app.hideMenu();
|
||||
},
|
||||
|
||||
/**
|
||||
* Maybe open the sidebar.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
maybeOpenSidebar() {
|
||||
// If the sidebar is already open, do nothing.
|
||||
if ( ! el.$sidebarToggle.parent().hasClass( 'wpforms-panel-sidebar-closed' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
el.$sidebarToggle.trigger( 'click' );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPForms.Admin.Builder.ContextMenu.init();
|
||||
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,919 @@
|
||||
/* global wpforms_builder, WPFormsBuilder, WPFormsUtils */
|
||||
|
||||
/**
|
||||
* @param wpforms_builder.field_cannot_be_reordered
|
||||
*/
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
/**
|
||||
* Form Builder Fields Drag-n-Drop module.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
|
||||
var WPForms = window.WPForms || {}; // eslint-disable-line no-var
|
||||
|
||||
WPForms.Admin = WPForms.Admin || {};
|
||||
WPForms.Admin.Builder = WPForms.Admin.Builder || {};
|
||||
|
||||
WPForms.Admin.Builder.DragFields = WPForms.Admin.Builder.DragFields || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
let el = {};
|
||||
|
||||
/**
|
||||
* Runtime variables.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const vars = {};
|
||||
|
||||
/**
|
||||
* Layout field functions wrapper.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
let fieldLayout; // eslint-disable-line prefer-const
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* DOM is fully loaded.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
ready() {
|
||||
app.setup();
|
||||
app.initSortableFields();
|
||||
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup. Prepare some variables.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
setup() {
|
||||
// Cache DOM elements.
|
||||
el = {
|
||||
$builder: $( '#wpforms-builder' ),
|
||||
$sortableFieldsWrap: $( '#wpforms-panel-fields .wpforms-field-wrap' ),
|
||||
$addFieldsButtons: $( '.wpforms-add-fields-button' ).not( '.not-draggable' ).not( '.warning-modal' ).not( '.education-modal' ),
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
events() {
|
||||
el.$builder
|
||||
.on( 'wpformsFieldDragToggle', app.fieldDragToggleEvent )
|
||||
.on( 'wpformsFieldAdd', function( e, id, type ) {
|
||||
// If a layout field is added, initialize its columns.
|
||||
if ( type === 'layout' ) {
|
||||
setTimeout( function() {
|
||||
$( '#wpforms-field-' + id ).find( '.wpforms-layout-column' ).each( function() {
|
||||
app.initSortableHandler( $( this ) );
|
||||
$( this ).sortable( 'enable' );
|
||||
} );
|
||||
}, 100 );
|
||||
}
|
||||
} );
|
||||
|
||||
$( document ).on( 'wpformsLayoutPresetChanged', app.layoutPresetChanged );
|
||||
},
|
||||
|
||||
/**
|
||||
* Disable drag & drop.
|
||||
*
|
||||
* @since 1.7.1
|
||||
* @since 1.7.7 Moved from admin-builder.js.
|
||||
*/
|
||||
disableDragAndDrop() {
|
||||
el.$sortableFieldsWrap.trigger( 'initSortableImmediately' );
|
||||
|
||||
el.$addFieldsButtons.filter( '.ui-draggable' ).draggable( 'disable' );
|
||||
|
||||
el.$sortableFieldsWrap.sortable( 'disable' );
|
||||
|
||||
if ( el.$sortableFieldsWrap.find( '.wpforms-layout-column.ui-sortable' ).data( 'ui-sortable' ) ) {
|
||||
el.$sortableFieldsWrap.find( '.wpforms-layout-column.ui-sortable' ).sortable( 'disable' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Enable drag & drop.
|
||||
*
|
||||
* @since 1.7.1
|
||||
* @since 1.7.7 Moved from admin-builder.js.
|
||||
*/
|
||||
enableDragAndDrop() {
|
||||
el.$addFieldsButtons.filter( '.ui-draggable' ).draggable( 'enable' );
|
||||
el.$sortableFieldsWrap.sortable( 'enable' );
|
||||
el.$sortableFieldsWrap.find( '.wpforms-layout-column.ui-sortable' ).sortable( 'enable' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Show popup in case if field is not draggable, and cancel moving.
|
||||
*
|
||||
* @since 1.7.5
|
||||
* @since 1.7.7 Moved from admin-builder.js.
|
||||
*
|
||||
* @param {jQuery} $field A field or list of fields.
|
||||
* @param {boolean} showPopUp Whether the pop-up should be displayed on dragging attempt.
|
||||
*/
|
||||
fieldDragDisable( $field, showPopUp = true ) {
|
||||
if ( $field.hasClass( 'ui-draggable-disabled' ) ) {
|
||||
// noinspection JSUnresolvedReference
|
||||
$field.draggable( 'enable' );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let startTopPosition;
|
||||
|
||||
// noinspection JSUnresolvedReference
|
||||
$field.draggable( {
|
||||
revert: true,
|
||||
axis: 'y',
|
||||
delay: 100,
|
||||
opacity: 1,
|
||||
cursor: 'move',
|
||||
start( event, ui ) {
|
||||
startTopPosition = ui.position.top;
|
||||
},
|
||||
drag( event, ui ) {
|
||||
if ( Math.abs( ui.position.top ) - Math.abs( startTopPosition ) > 15 ) {
|
||||
if ( showPopUp ) {
|
||||
app.youCantReorderFieldPopup();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Allow field dragging.
|
||||
*
|
||||
* @since 1.7.5
|
||||
* @since 1.7.7 Moved from admin-builder.js.
|
||||
*
|
||||
* @param {jQuery} $field A field or list of fields.
|
||||
*/
|
||||
fieldDragEnable( $field ) {
|
||||
if ( $field.hasClass( 'ui-draggable' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// noinspection JSUnresolvedReference
|
||||
$field.draggable( 'disable' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Show the error message in the popup that you cannot reorder the field.
|
||||
*
|
||||
* @since 1.7.1
|
||||
* @since 1.7.7 Moved from admin-builder.js.
|
||||
*/
|
||||
youCantReorderFieldPopup() {
|
||||
$.confirm( {
|
||||
title: wpforms_builder.heads_up,
|
||||
content: wpforms_builder.field_cannot_be_reordered,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'red',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_builder.ok,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler for `wpformsFieldDragToggle` event.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
* @param {number|string} id Field ID.
|
||||
*/
|
||||
fieldDragToggleEvent( e, id ) {
|
||||
const $field = $( `#wpforms-field-${ id }` );
|
||||
|
||||
if (
|
||||
$field.hasClass( 'wpforms-field-not-draggable' ) ||
|
||||
$field.hasClass( 'wpforms-field-stick' )
|
||||
) {
|
||||
app.fieldDragDisable( $field );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
app.fieldDragEnable( $field );
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize sortable fields in the builder form preview area.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
initSortableFields() {
|
||||
app.initSortableContainer( el.$sortableFieldsWrap );
|
||||
|
||||
// Function to initialize all layout columns.
|
||||
const initAllLayoutColumns = function() {
|
||||
el.$builder.find( '.wpforms-layout-column' ).each( function() {
|
||||
app.initSortableHandler( $( this ) );
|
||||
$( this ).sortable( 'enable' );
|
||||
} );
|
||||
};
|
||||
|
||||
// Initialize immediately.
|
||||
initAllLayoutColumns();
|
||||
|
||||
// And again after a short delay to ensure all DOM elements are loaded.
|
||||
setTimeout( initAllLayoutColumns, 500 );
|
||||
|
||||
app.fieldDragDisable( $( '.wpforms-field-not-draggable, .wpforms-field-stick' ) );
|
||||
app.initDraggableFields();
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize sortable container with fields.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @param {jQuery} $sortable Container to make sortable.
|
||||
*/
|
||||
async initSortableContainer( $sortable ) {
|
||||
app.initSortableHandler( $sortable );
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler for `wpformsLayoutPresetChanged` event.
|
||||
*
|
||||
* @since 1.9.6
|
||||
*
|
||||
* @param {Object} event Event object.
|
||||
* @param {Object} fieldOptions Field options.
|
||||
*/
|
||||
async layoutPresetChanged( event, fieldOptions ) { // eslint-disable-line no-unused-vars
|
||||
const $fieldOptions = $( fieldOptions ),
|
||||
fieldId = $fieldOptions.data( 'field-id' ),
|
||||
$sortable = $( `#wpforms-field-${ fieldId } .wpforms-layout-column` );
|
||||
|
||||
// Immediately initialize all columns in this layout.
|
||||
$sortable.each( function() {
|
||||
app.initSortableHandler( $( this ) );
|
||||
|
||||
// Make sure sortable is not disabled, prevents from double initialization.
|
||||
$( this ).sortable( 'enable' );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize sortable handler.
|
||||
*
|
||||
* @since 1.9.6
|
||||
*
|
||||
* @param {jQuery} $sortable Sortable container.
|
||||
*/
|
||||
initSortableHandler( $sortable ) { // eslint-disable-line max-lines-per-function
|
||||
const $fieldOptions = $( '#wpforms-field-options' );
|
||||
const $scrollContainer = $( '#wpforms-panel-fields .wpforms-panel-content-wrap' );
|
||||
|
||||
let fieldId,
|
||||
fieldType,
|
||||
isNewField,
|
||||
$fieldOption,
|
||||
$prevFieldOption,
|
||||
prevFieldId,
|
||||
currentlyScrolling = false;
|
||||
|
||||
$sortable.sortable( {
|
||||
items: '> .wpforms-field:not(.wpforms-field-stick):not(.no-fields-preview)',
|
||||
connectWith: '.wpforms-field-wrap, .wpforms-layout-column',
|
||||
delay: 100,
|
||||
opacity: 1,
|
||||
cursor: 'move',
|
||||
cancel: '.wpforms-field-not-draggable',
|
||||
placeholder: 'wpforms-field-drag-placeholder',
|
||||
appendTo: '#wpforms-panel-fields',
|
||||
zindex: 10000,
|
||||
tolerance: 'pointer',
|
||||
distance: 1,
|
||||
start( e, ui ) {
|
||||
fieldId = ui.item.data( 'field-id' );
|
||||
fieldType = ui.item.data( 'field-type' );
|
||||
isNewField = typeof fieldId === 'undefined';
|
||||
$fieldOption = $( '#wpforms-field-option-' + fieldId );
|
||||
|
||||
vars.fieldReceived = false;
|
||||
vars.fieldRejected = false;
|
||||
vars.$sortableStart = $sortable;
|
||||
vars.startPosition = ui.item.first().index();
|
||||
|
||||
el.$builder.trigger( 'wpformsFieldDragStart', [ fieldId ] );
|
||||
},
|
||||
beforeStop( e, ui ) {
|
||||
if ( ! vars.glitchChange ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Before processing in the `stop` method, we need to perform the last check.
|
||||
if ( ! fieldLayout.isFieldAllowedInColum( fieldType, ui.item.first().parent() ) ) {
|
||||
vars.fieldRejected = true;
|
||||
}
|
||||
},
|
||||
stop( e, ui ) { // eslint-disable-line complexity
|
||||
const $field = ui.item.first();
|
||||
const $parent = $field.parent();
|
||||
|
||||
// If this is a layout field, initialize its columns.
|
||||
if ( $field.hasClass( 'wpforms-field-layout' ) ) {
|
||||
$field.find( '.wpforms-layout-column' ).each( function() {
|
||||
app.initSortableHandler( $( this ) );
|
||||
$( this ).sortable( 'enable' );
|
||||
} );
|
||||
}
|
||||
|
||||
// If the field is in the main container but was attempted to be added to a column, move it to the column.
|
||||
if (
|
||||
$parent.hasClass( 'wpforms-field-wrap' ) &&
|
||||
window.wpformsLastReceive &&
|
||||
window.wpformsLastReceive.isColumn &&
|
||||
! $field.hasClass( 'wpforms-field-layout' ) &&
|
||||
! $field.hasClass( 'wpforms-field-repeater' )
|
||||
) {
|
||||
// Move the field to the column that was last trying to receive it.
|
||||
$field.detach();
|
||||
window.wpformsLastReceive.sortable.append( $field );
|
||||
|
||||
// Mark the field as rejected to prevent further processing in the main container.
|
||||
vars.fieldRejected = true;
|
||||
|
||||
// Reset tracking variables.
|
||||
window.wpformsLastReceive = null;
|
||||
window.wpformsLastReceiveForMainWrap = null;
|
||||
}
|
||||
|
||||
ui.placeholder.removeClass( 'wpforms-field-drag-not-allowed' );
|
||||
$field.removeClass( 'wpforms-field-drag-not-allowed' );
|
||||
|
||||
// Reject not allowed fields.
|
||||
if ( vars.fieldRejected ) {
|
||||
const $targetColumn = isNewField ? $sortable : $field.parent();
|
||||
|
||||
app.revertMoveFieldToColumn( $field );
|
||||
el.$builder.trigger( 'wpformsFieldMoveRejected', [ $field, ui, $targetColumn ] );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
prevFieldId = $field.prev( '.wpforms-field, .wpforms-alert' ).data( 'field-id' );
|
||||
$prevFieldOption = $( `#wpforms-field-option-${ prevFieldId }` );
|
||||
|
||||
if ( $prevFieldOption.length > 0 ) {
|
||||
$prevFieldOption.after( $fieldOption );
|
||||
} else {
|
||||
$fieldOptions.prepend( $fieldOption );
|
||||
}
|
||||
|
||||
// In the case of changing fields' order inside the same column,
|
||||
// we just need to change the position of the field.
|
||||
if ( ! isNewField && $field.closest( '.wpforms-layout-column' ).is( $sortable ) ) {
|
||||
fieldLayout.positionFieldInColumn(
|
||||
fieldId,
|
||||
$field.index() - 1,
|
||||
$sortable
|
||||
);
|
||||
}
|
||||
|
||||
const $layoutField = $field.closest( '.wpforms-field-layout, .wpforms-field-repeater' );
|
||||
|
||||
fieldLayout.fieldOptionsUpdate( null, fieldId );
|
||||
fieldLayout.reorderLayoutFieldsOptions( $layoutField );
|
||||
|
||||
if ( ! isNewField ) {
|
||||
$field
|
||||
.removeClass( 'wpforms-field-dragging' )
|
||||
.removeClass( 'wpforms-field-drag-over' );
|
||||
}
|
||||
|
||||
$field.attr( 'style', '' );
|
||||
|
||||
el.$builder.trigger( 'wpformsFieldMove', ui );
|
||||
|
||||
vars.fieldReceived = false;
|
||||
},
|
||||
over( e, ui ) { // eslint-disable-line complexity
|
||||
const $field = ui.item.first(),
|
||||
$target = $( e.target ),
|
||||
$placeholder = $target.find( '.wpforms-field-drag-placeholder' ),
|
||||
isColumn = $target.hasClass( 'wpforms-layout-column' ),
|
||||
helper = {
|
||||
width: $target.outerWidth(),
|
||||
height: $field.outerHeight(),
|
||||
};
|
||||
|
||||
let targetClass = isColumn ? ' wpforms-field-drag-to-column' : '';
|
||||
|
||||
if ( isColumn ) {
|
||||
const columnSize = $target.attr( 'class' ).match( /wpforms-layout-column-(\d+)/ )[ 1 ];
|
||||
|
||||
targetClass += ` wpforms-field-drag-to-column-${ columnSize }`;
|
||||
targetClass += ` wpforms-field-drag-to-${ $target.parents( '.wpforms-field' ).data( 'field-type' ) }`;
|
||||
}
|
||||
|
||||
fieldId = $field.data( 'field-id' );
|
||||
fieldType = $field.data( 'field-type' ) || vars.fieldType;
|
||||
isNewField = typeof fieldId === 'undefined';
|
||||
|
||||
// Adjust helper size according to the placeholder size.
|
||||
$field
|
||||
.addClass( 'wpforms-field-dragging' + targetClass );
|
||||
|
||||
if ( ! isColumn || ! fieldLayout.isLayoutBasedField( fieldType ) ) {
|
||||
$field
|
||||
.css( {
|
||||
width: isColumn ? helper.width - 5 : helper.width,
|
||||
height: 'auto',
|
||||
} );
|
||||
}
|
||||
|
||||
const placeholderHeight = isColumn ? 90 : helper.height;
|
||||
|
||||
// Adjust placeholder height according to the height of the helper.
|
||||
$placeholder
|
||||
.removeClass( 'wpforms-field-drag-not-allowed' )
|
||||
.css( {
|
||||
height: isNewField ? placeholderHeight + 18 : helper.height,
|
||||
} );
|
||||
|
||||
// Drop to this place is not allowed.
|
||||
if ( isColumn && ! fieldLayout.isFieldAllowedInColum( fieldType, $target ) ) {
|
||||
$placeholder.addClass( 'wpforms-field-drag-not-allowed' );
|
||||
$field.addClass( 'wpforms-field-drag-not-allowed' );
|
||||
}
|
||||
|
||||
el.$builder.trigger( 'wpformsFieldDragOver', [ fieldId, $target ] );
|
||||
|
||||
// Skip if it is the existing field.
|
||||
if ( ! isNewField ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$field
|
||||
.addClass( 'wpforms-field-drag-over' )
|
||||
.removeClass( 'wpforms-field-drag-out' );
|
||||
},
|
||||
out( e, ui ) {
|
||||
const $field = ui.item.first(),
|
||||
// eslint-disable-next-line no-shadow
|
||||
fieldId = $field.data( 'field-id' ),
|
||||
// eslint-disable-next-line no-shadow
|
||||
isNewField = typeof fieldId === 'undefined';
|
||||
|
||||
$field
|
||||
.removeClass( 'wpforms-field-drag-not-allowed' )
|
||||
.removeClass( 'wpforms-field-drag-to-repeater' )
|
||||
.removeClass( 'wpforms-field-drag-to-layout' )
|
||||
.removeClass( app.getDragColumnClasses( $field.attr( 'class' ) ) );
|
||||
|
||||
if ( vars.fieldReceived ) {
|
||||
$field.attr( 'style', '' );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip if it is the existing field.
|
||||
if ( ! isNewField ) {
|
||||
// Remove extra class from the parent layout field.
|
||||
// Fixes disappearing of duplicate/delete field icons
|
||||
// after moving the field outside the layout field.
|
||||
$( ui.sender )
|
||||
.closest( '.wpforms-field-layout, .wpforms-field-repeater' )
|
||||
.removeClass( 'wpforms-field-child-hovered' );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$field
|
||||
.addClass( 'wpforms-field-drag-out' )
|
||||
.removeClass( 'wpforms-field-drag-over' );
|
||||
},
|
||||
receive( e, ui ) { // eslint-disable-line complexity
|
||||
const $field = $( ui.helper || ui.item );
|
||||
const isColumn = $sortable.hasClass( 'wpforms-layout-column' );
|
||||
const isMainWrap = $sortable.hasClass( 'wpforms-field-wrap' );
|
||||
|
||||
// Save current field receive as the last one.
|
||||
window.wpformsLastReceive = {
|
||||
isColumn,
|
||||
isMainWrap,
|
||||
sender: ui.sender ? $( ui.sender ).attr( 'class' ) : null,
|
||||
sortable: $sortable,
|
||||
time: new Date().getTime(),
|
||||
};
|
||||
|
||||
// Check if this is a second receive for a field that was already handled by the main container.
|
||||
if (
|
||||
isColumn &&
|
||||
window.wpformsLastReceiveForMainWrap &&
|
||||
( new Date().getTime() - window.wpformsLastReceiveForMainWrap.time < 100 )
|
||||
) {
|
||||
// We need to stop this receive and cancel the operation for the main container.
|
||||
// Mark the field as rejected, which will cause it to be removed from the main container.
|
||||
vars.fieldRejected = true;
|
||||
window.wpformsLastReceiveForMainWrap = null;
|
||||
window.wpformsLastReceive = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is the main container, remember this event.
|
||||
if ( isMainWrap ) {
|
||||
window.wpformsLastReceiveForMainWrap = window.wpformsLastReceive;
|
||||
}
|
||||
|
||||
fieldId = $field.data( 'field-id' );
|
||||
fieldType = $field.data( 'field-type' ) || vars.fieldType;
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
const isNewField = typeof fieldId === 'undefined';
|
||||
|
||||
// Drop to this place is not allowed.
|
||||
if (
|
||||
isColumn &&
|
||||
! fieldLayout.isFieldAllowedInColum( fieldType, $sortable )
|
||||
) {
|
||||
vars.fieldRejected = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
vars.fieldReceived = true;
|
||||
|
||||
$field.removeClass( 'wpforms-field-drag-over' );
|
||||
|
||||
// Move existing field.
|
||||
if ( ! isNewField ) {
|
||||
fieldLayout.receiveFieldToColumn(
|
||||
fieldId,
|
||||
ui.item.index() - 1,
|
||||
$field.parent()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Add new field.
|
||||
const position = $sortable.data( 'ui-sortable' )?.currentItem?.index() || 0;
|
||||
|
||||
$field
|
||||
.addClass( 'wpforms-field-drag-over wpforms-field-drag-pending' )
|
||||
.removeClass( 'wpforms-field-drag-out' )
|
||||
.append( WPFormsBuilder.settings.spinnerInline )
|
||||
.css( 'width', '100%' );
|
||||
|
||||
el.$builder.find( '.no-fields-preview' ).remove();
|
||||
|
||||
WPFormsBuilder.fieldAdd(
|
||||
vars.fieldType,
|
||||
{
|
||||
position: isColumn ? position - 1 : position,
|
||||
placeholder: $field,
|
||||
$sortable,
|
||||
}
|
||||
);
|
||||
|
||||
vars.fieldType = undefined;
|
||||
},
|
||||
change( e, ui ) {
|
||||
const $placeholderSortable = ui.placeholder.parent();
|
||||
const $targetSortable = $( e.target );
|
||||
|
||||
vars.glitchChange = false;
|
||||
|
||||
// In some cases sortable widget display placeholder in wrong sortable instance.
|
||||
// It's happens when you drag the field over/out the last column of the last Layout field.
|
||||
if (
|
||||
! $sortable.is( $placeholderSortable ) &&
|
||||
$sortable.hasClass( 'wpforms-field-wrap' ) &&
|
||||
$placeholderSortable.hasClass( 'wpforms-layout-column' )
|
||||
) {
|
||||
vars.glitchChange = true;
|
||||
}
|
||||
|
||||
el.$builder.trigger( 'wpformsFieldDragChange', [ fieldId, $targetSortable ] );
|
||||
},
|
||||
sort( e ) {
|
||||
if ( currentlyScrolling ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const scrollAreaHeight = 50,
|
||||
mouseYPosition = e.clientY,
|
||||
containerOffset = $scrollContainer.offset(),
|
||||
containerHeight = $scrollContainer.height(),
|
||||
containerBottom = containerOffset.top + containerHeight;
|
||||
|
||||
let operator;
|
||||
|
||||
if (
|
||||
mouseYPosition > containerOffset.top &&
|
||||
mouseYPosition < ( containerOffset.top + scrollAreaHeight )
|
||||
) {
|
||||
operator = '-=';
|
||||
} else if (
|
||||
mouseYPosition > ( containerBottom - scrollAreaHeight ) &&
|
||||
mouseYPosition < containerBottom
|
||||
) {
|
||||
operator = '+=';
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
currentlyScrolling = true;
|
||||
|
||||
$scrollContainer.animate(
|
||||
{
|
||||
scrollTop: operator + ( containerHeight / 3 ) + 'px',
|
||||
},
|
||||
800,
|
||||
function() {
|
||||
currentlyScrolling = false;
|
||||
}
|
||||
);
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove all classes starting with `wpforms-field-drag-to-column`.
|
||||
*
|
||||
* @since 1.9.6
|
||||
*
|
||||
* @param {string} className The class name of the field.
|
||||
*
|
||||
* @return {string} The class name of the field.
|
||||
*/
|
||||
getDragColumnClasses( className ) {
|
||||
return ( className.match( /wpforms-field-drag-to-column(-\d+|)/g ) || [] ).join( ' ' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize draggable fields buttons.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
initDraggableFields() {
|
||||
el.$addFieldsButtons.draggable( {
|
||||
connectToSortable: '.wpforms-field-wrap, .wpforms-layout-column',
|
||||
delay: 200,
|
||||
cancel: false,
|
||||
scroll: false,
|
||||
opacity: 1,
|
||||
appendTo: '#wpforms-panel-fields',
|
||||
zindex: 10000,
|
||||
|
||||
helper() {
|
||||
const $this = $( this );
|
||||
const $el = $( '<div class="wpforms-field-drag-out wpforms-field-drag">' );
|
||||
|
||||
vars.fieldType = $this.data( 'field-type' );
|
||||
|
||||
return $el.html( $this.html() );
|
||||
},
|
||||
|
||||
start( e, ui ) {
|
||||
const event = WPFormsUtils.triggerEvent(
|
||||
el.$builder,
|
||||
'wpformsFieldAddDragStart',
|
||||
[ vars.fieldType, ui ]
|
||||
);
|
||||
|
||||
// Allow callbacks on `wpformsFieldAddDragStart` to cancel dragging the field
|
||||
// by triggering `event.preventDefault()`.
|
||||
if ( event.isDefaultPrevented() ) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
stop( e, ui ) {
|
||||
const event = WPFormsUtils.triggerEvent(
|
||||
el.$builder,
|
||||
'wpformsFieldAddDragStop',
|
||||
[ vars.fieldType, ui ]
|
||||
);
|
||||
|
||||
// Allow callbacks on `wpformsFieldAddDragStop` to cancel dragging the field
|
||||
// by triggering `event.preventDefault()`.
|
||||
if ( event.isDefaultPrevented() ) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Revert moving the field to the column.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @param {jQuery} $field Field object.
|
||||
*/
|
||||
revertMoveFieldToColumn( $field ) {
|
||||
const isNewField = $field.data( 'field-id' ) === undefined;
|
||||
|
||||
if ( isNewField ) {
|
||||
// Remove the field.
|
||||
$field.remove();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Restore existing field on the previous position.
|
||||
$field = $field.detach();
|
||||
|
||||
const $fieldInStartPosition = vars.$sortableStart
|
||||
.find( '> .wpforms-field' )
|
||||
.eq( vars.startPosition );
|
||||
|
||||
$field
|
||||
.removeClass( 'wpforms-field-dragging' )
|
||||
.removeClass( 'wpforms-field-drag-over' )
|
||||
.attr( 'style', '' );
|
||||
|
||||
if ( $fieldInStartPosition.length ) {
|
||||
$fieldInStartPosition.before( $field );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
vars.$sortableStart.append( $field );
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Layout field functions holder.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
fieldLayout = {
|
||||
|
||||
/**
|
||||
* Position field in the column inside the Layout Field.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @param {number} fieldId Field ID.
|
||||
* @param {number} position The new position of the field inside the column.
|
||||
* @param {jQuery} $sortable Sortable column container.
|
||||
*/
|
||||
positionFieldInColumn( fieldId, position, $sortable ) {
|
||||
if ( ! WPForms.Admin.Builder.FieldLayout ) {
|
||||
return;
|
||||
}
|
||||
|
||||
WPForms.Admin.Builder.FieldLayout.positionFieldInColumn( fieldId, position, $sortable );
|
||||
},
|
||||
|
||||
/**
|
||||
* Receive field to column inside the Layout Field.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @param {number} fieldId Field ID.
|
||||
* @param {number} position Field position inside the column.
|
||||
* @param {jQuery} $sortable Sortable column container.
|
||||
*/
|
||||
receiveFieldToColumn( fieldId, position, $sortable ) {
|
||||
if ( ! WPForms.Admin.Builder.FieldLayout ) {
|
||||
return;
|
||||
}
|
||||
|
||||
WPForms.Admin.Builder.FieldLayout.receiveFieldToColumn( fieldId, position, $sortable );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update field options according to the position of the field.
|
||||
* Event `wpformsFieldOptionTabToggle` handler.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @param {Event} e Event.
|
||||
* @param {number} fieldId Field id.
|
||||
*/
|
||||
fieldOptionsUpdate( e, fieldId ) {
|
||||
if ( ! WPForms.Admin.Builder.FieldLayout ) {
|
||||
return;
|
||||
}
|
||||
|
||||
WPForms.Admin.Builder.FieldLayout.fieldOptionsUpdate( e, fieldId );
|
||||
},
|
||||
|
||||
/**
|
||||
* Reorder fields options of the fields in columns.
|
||||
* It is not critical, but it's better to keep some order in the `fields` data array.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @param {jQuery} $layoutField Layout field object.
|
||||
*/
|
||||
reorderLayoutFieldsOptions( $layoutField ) {
|
||||
if ( ! WPForms.Admin.Builder.FieldLayout ) {
|
||||
return;
|
||||
}
|
||||
|
||||
WPForms.Admin.Builder.FieldLayout.reorderLayoutFieldsOptions( $layoutField );
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether the field type is allowed to be in column.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @param {string} fieldType Field type to check.
|
||||
* @param {jQuery} $targetColumn Target column element.
|
||||
*
|
||||
* @return {boolean} True if allowed.
|
||||
*/
|
||||
isFieldAllowedInColum( fieldType, $targetColumn ) {
|
||||
if ( ! WPForms.Admin.Builder.FieldLayout ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const isAllowed = WPForms.Admin.Builder.FieldLayout.isFieldAllowedInColum( fieldType, $targetColumn );
|
||||
|
||||
/**
|
||||
* Allows developers to determine whether the field is allowed to be dragged in column.
|
||||
*
|
||||
* @since 1.8.9
|
||||
*
|
||||
* @param {boolean} isAllowed Whether the field is allowed to be placed in the column.
|
||||
* @param {string} fieldType Field type.
|
||||
* @param {jQuery} $targetColumn Target column element.
|
||||
*
|
||||
* @return {boolean} True if allowed.
|
||||
*/
|
||||
return wp.hooks.applyFilters( 'wpforms.LayoutField.isFieldAllowedDragInColumn', isAllowed, fieldType, $targetColumn );
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine whether the field type is a layout-based field.
|
||||
*
|
||||
* @since 1.8.9
|
||||
*
|
||||
* @param {string} fieldType Field type to check.
|
||||
*
|
||||
* @return {boolean} True if it is the Layout-based field.
|
||||
*/
|
||||
isLayoutBasedField( fieldType ) {
|
||||
if ( ! WPForms.Admin.Builder.FieldLayout ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return WPForms.Admin.Builder.FieldLayout.isLayoutBasedField( fieldType );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPForms.Admin.Builder.DragFields.init();
|
||||
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,389 @@
|
||||
/* global List, wpforms_builder */
|
||||
/**
|
||||
* WPForms Builder Dropdown List module.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*/
|
||||
|
||||
/*
|
||||
Usage:
|
||||
|
||||
dropdownList = WPForms.Admin.Builder.DropdownList.init( {
|
||||
class: 'insert-field-dropdown', // Additional CSS class.
|
||||
title: 'Dropdown Title', // Dropdown title.
|
||||
list: [ // Items list.
|
||||
{ value: '1', text: 'Item 1' },
|
||||
{ value: '2', text: 'Item 2' },
|
||||
{ value: '3', text: 'Item 3' },
|
||||
],
|
||||
container: $( '.holder-container' ), // Holder container. Optional.
|
||||
scrollableContainer: $( '.scrollable-container' ), // Scrollable container. Optional.
|
||||
search: {
|
||||
enabled: false, // Enable search. Optional.
|
||||
searchBy : [], // Search by fields.
|
||||
placeholder: 'Search', // Search input placeholder.
|
||||
noResultsText: 'Sorry, no results found', // No results text.
|
||||
},
|
||||
button: $( '.button' ), // Button.
|
||||
buttonDistance: 21, // Distance from dropdown to the button.
|
||||
noLeftOffset: false, // Disable left offset for the dropdown.
|
||||
itemFormat( item ) { // Item element renderer. Optional.
|
||||
return `<span>${ item.text }</span>`;
|
||||
},
|
||||
onSelect( event, value, text, $item, instance ) { // On select event handler.
|
||||
console.log( 'Item selected:', text );
|
||||
instance.close();
|
||||
$button.removeClass( 'active' );
|
||||
},
|
||||
} );
|
||||
*/
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
var WPForms = window.WPForms || {}; // eslint-disable-line no-var
|
||||
|
||||
WPForms.Admin = WPForms.Admin || {};
|
||||
WPForms.Admin.Builder = WPForms.Admin.Builder || {};
|
||||
|
||||
WPForms.Admin.Builder.DropdownList = WPForms.Admin.Builder.DropdownList || ( function( document, window, $ ) {
|
||||
/**
|
||||
* DropdownList object constructor.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
function DropdownList( options ) { // eslint-disable-line max-lines-per-function
|
||||
const self = this;
|
||||
|
||||
/**
|
||||
* Default options.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const defaultOptions = {
|
||||
class: '',
|
||||
title: '',
|
||||
list: [],
|
||||
container: null,
|
||||
scrollableContainer: null,
|
||||
search: {
|
||||
enabled: false,
|
||||
searchBy : [],
|
||||
placeholder: wpforms_builder.search,
|
||||
noResultsText: wpforms_builder.no_results_found,
|
||||
},
|
||||
button: null,
|
||||
buttonDistance: 10,
|
||||
noLeftOffset: false,
|
||||
onSelect: null,
|
||||
itemFormat( item ) {
|
||||
return item.text;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Options.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*
|
||||
* @type {jQuery}
|
||||
*/
|
||||
self.options = $.extend( defaultOptions, options );
|
||||
|
||||
/**
|
||||
* Main dropdown container.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*
|
||||
* @type {jQuery}
|
||||
*/
|
||||
self.$el = null;
|
||||
|
||||
/**
|
||||
* Form builder container.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*
|
||||
* @type {jQuery}
|
||||
*/
|
||||
self.$builder = $( '#wpforms-builder' );
|
||||
|
||||
/**
|
||||
* List.js instance.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
self.searchItems = null;
|
||||
|
||||
/**
|
||||
* Close the dropdown.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*/
|
||||
self.close = function() {
|
||||
self.$el.addClass( 'closed' );
|
||||
|
||||
// Clear search input.
|
||||
if ( self.options.search.enabled ) {
|
||||
self.clearSearch();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Open the dropdown.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*/
|
||||
self.open = function() {
|
||||
self.$el.removeClass( 'closed open-down' );
|
||||
self.setPosition();
|
||||
|
||||
// Close dropdown on click outside.
|
||||
self.$builder.on( 'click.DropdownList', function( e ) {
|
||||
const $target = $( e.target );
|
||||
const excludedSelectors = '.button-insert-field, .wpforms-smart-tags-enabled, .wpforms-show-smart-tags, .mce-ico';
|
||||
|
||||
if ( $target.closest( self.$el ).length || $target.is( excludedSelectors ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.$builder.off( 'click.DropdownList' );
|
||||
|
||||
const $button = $( self.options.button );
|
||||
|
||||
if ( $button.hasClass( 'active' ) ) {
|
||||
$button.trigger( 'click' );
|
||||
}
|
||||
} );
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate the dropdown HTML.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*
|
||||
* @return {string} HTML.
|
||||
*/
|
||||
self.generateHtml = function() {
|
||||
const list = self.options.list;
|
||||
|
||||
if ( ! list || list.length === 0 ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const itemFormat = typeof self.options.itemFormat === 'function' ? self.options.itemFormat : defaultOptions.itemFormat;
|
||||
|
||||
// Generate HTML list items.
|
||||
const items = list.map( ( item ) => `<li data-value='${ item.value }'>${ itemFormat( item ) }</li>` );
|
||||
|
||||
// Generate search HTML if enabled.
|
||||
const searchHtml = self.options.search.enabled
|
||||
? `<div class="wpforms-builder-dropdown-list-search-container">
|
||||
<input type="search" class="wpforms-builder-dropdown-list-search-input" placeholder="${ self.options.search.placeholder }">
|
||||
<i class="fa fa-times-circle wpforms-builder-dropdown-list-search-close" aria-hidden="true"></i>
|
||||
</div>`
|
||||
: '';
|
||||
|
||||
const listClass = self.options.search.enabled ? 'list' : '';
|
||||
|
||||
return `<div class="wpforms-builder-dropdown-list closed ${ self.options.class }">
|
||||
<div class="title">${ self.options.title }</div>
|
||||
${ searchHtml }
|
||||
<ul class="${ listClass }">${ items.join( '' ) }</ul>
|
||||
<div class="wpforms-no-results">${ self.options.search.noResultsText }</div>
|
||||
</div>`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Attach dropdown to DOM.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*/
|
||||
self.attach = function() {
|
||||
const html = self.generateHtml();
|
||||
|
||||
// Remove old dropdown.
|
||||
if ( self.$el && self.$el.length ) {
|
||||
self.$el.remove();
|
||||
}
|
||||
|
||||
// Create jQuery objects.
|
||||
self.$el = $( html );
|
||||
self.$button = $( self.options.button );
|
||||
self.$container = self.options.container ? $( self.options.container ) : self.$button.parent();
|
||||
self.$scrollableContainer = self.options.scrollableContainer ? $( self.options.scrollableContainer ) : null;
|
||||
|
||||
// Init List.js if search is enabled.
|
||||
if ( self.options.search.enabled ) {
|
||||
self.searchItems = new List( self.$el[ 0 ], {
|
||||
valueNames: self.options.search.searchBy,
|
||||
} );
|
||||
}
|
||||
|
||||
// Add the dropdown to the container.
|
||||
self.$container.append( self.$el );
|
||||
|
||||
self.setPosition();
|
||||
};
|
||||
|
||||
/**
|
||||
* Set dropdown position.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*/
|
||||
self.setPosition = function() {
|
||||
// Calculate position.
|
||||
const buttonOffset = self.$button.offset(),
|
||||
containerOffset = self.$container.offset(),
|
||||
containerPosition = self.$container.position(),
|
||||
dropdownHeight = self.$el.height(),
|
||||
scrollTop = self.$scrollableContainer ? self.$scrollableContainer.scrollTop() : 0;
|
||||
|
||||
let top = buttonOffset.top - containerOffset.top - dropdownHeight - self.options.buttonDistance;
|
||||
|
||||
// In the case of the dropdown doesn't fit into the scrollable container to top,
|
||||
// it is necessary to open the dropdown to the bottom.
|
||||
if ( scrollTop + containerPosition.top - dropdownHeight < 0 ) {
|
||||
top = buttonOffset.top - containerOffset.top + self.$button.height() + self.options.buttonDistance - 11;
|
||||
self.$el.addClass( 'open-down' );
|
||||
}
|
||||
|
||||
self.$el.css( 'top', top );
|
||||
|
||||
// If noLeftOffset is set, do not set `left` positioning value.
|
||||
if ( self.options.noLeftOffset ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The dropdown is outside the field options, it is necessary to set `left` positioning value.
|
||||
if ( self.$container.closest( '.wpforms-field-option' ).length === 0 ) {
|
||||
self.$el.css( 'left', buttonOffset.left - containerOffset.left );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Events.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*/
|
||||
self.events = function() {
|
||||
// Click (select) the item.
|
||||
self.$el.find( 'li' ).off()
|
||||
.on( 'click', function( event ) {
|
||||
// Bail if callback is not a function.
|
||||
if ( typeof self.options.onSelect !== 'function' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $item = $( this );
|
||||
|
||||
// Clear search input.
|
||||
if ( self.options.search.enabled ) {
|
||||
self.clearSearch();
|
||||
}
|
||||
|
||||
// Trigger callback.
|
||||
self.options.onSelect( event, $item.data( 'value' ), $item.text(), $item, self );
|
||||
} );
|
||||
|
||||
// Search.
|
||||
if ( self.options.search.enabled ) {
|
||||
self.$el.find( 'input[type="search"]' ).on( 'keyup search', self.search );
|
||||
self.$el.find( '.wpforms-builder-dropdown-list-search-close' ).on( 'click', self.clearSearch );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*
|
||||
* @param {Array} list List of items.
|
||||
*/
|
||||
self.init = function( list = null ) {
|
||||
self.options.list = list ? list : self.options.list;
|
||||
|
||||
self.attach();
|
||||
self.events();
|
||||
|
||||
self.$button.data( 'dropdown-list', self );
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroy.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*/
|
||||
self.destroy = function() {
|
||||
self.$button.data( 'dropdown-list', null );
|
||||
self.$el.remove();
|
||||
};
|
||||
|
||||
/**
|
||||
* Search.
|
||||
*
|
||||
* @since 1.9.5
|
||||
* @param {Object } event Event.
|
||||
*/
|
||||
self.search = function( event ) {
|
||||
const searchTerm = event.target.value.toLowerCase();
|
||||
const $noResults = self.$el.find( '.wpforms-no-results' );
|
||||
|
||||
// Show/hide close button.
|
||||
if ( searchTerm !== '' ) {
|
||||
self.$el.find( '.wpforms-builder-dropdown-list-search-close' ).addClass( 'active' );
|
||||
}
|
||||
|
||||
// Search.
|
||||
self.searchItems.search( searchTerm );
|
||||
|
||||
// Show/hide no result message.
|
||||
$noResults.toggle( self.searchItems.visibleItems.length === 0 );
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear search input.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*/
|
||||
self.clearSearch = function() {
|
||||
// Clear search input.
|
||||
self.$el.find( 'input[type="search"]' ).val( '' );
|
||||
self.$el.find( '.wpforms-no-results' ).hide();
|
||||
self.$el.find( '.wpforms-builder-dropdown-list-search-close' ).removeClass( 'active' );
|
||||
|
||||
// Clear search results.
|
||||
self.searchItems.search();
|
||||
};
|
||||
|
||||
// Initialize.
|
||||
self.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
return {
|
||||
|
||||
/**
|
||||
* Start the engine. DOM is not ready yet, use only to init something.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*
|
||||
* @param {Object} options Options.
|
||||
*
|
||||
* @return {Object} DropdownList instance.
|
||||
*/
|
||||
init( options ) {
|
||||
return new DropdownList( options );
|
||||
},
|
||||
};
|
||||
}( document, window, jQuery ) );
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
var WPForms=window.WPForms||{};WPForms.Admin=WPForms.Admin||{},WPForms.Admin.Builder=WPForms.Admin.Builder||{},WPForms.Admin.Builder.DropdownList=WPForms.Admin.Builder.DropdownList||(t=>{function o(e){let i=this,s={class:"",title:"",list:[],container:null,scrollableContainer:null,search:{enabled:!1,searchBy:[],placeholder:wpforms_builder.search,noResultsText:wpforms_builder.no_results_found},button:null,buttonDistance:10,noLeftOffset:!1,onSelect:null,itemFormat(e){return e.text}};i.options=t.extend(s,e),i.$el=null,i.$builder=t("#wpforms-builder"),i.searchItems=null,i.close=function(){i.$el.addClass("closed"),i.options.search.enabled&&i.clearSearch()},i.open=function(){i.$el.removeClass("closed open-down"),i.setPosition(),i.$builder.on("click.DropdownList",function(e){var e=t(e.target);e.closest(i.$el).length||e.is(".button-insert-field, .wpforms-smart-tags-enabled, .wpforms-show-smart-tags, .mce-ico")||(i.$builder.off("click.DropdownList"),(e=t(i.options.button)).hasClass("active")&&e.trigger("click"))})},i.generateHtml=function(){var e=i.options.list;if(!e||0===e.length)return"";let o=("function"==typeof i.options.itemFormat?i.options:s).itemFormat;var e=e.map(e=>`<li data-value='${e.value}'>${o(e)}</li>`),t=i.options.search.enabled?`<div class="wpforms-builder-dropdown-list-search-container">
|
||||
<input type="search" class="wpforms-builder-dropdown-list-search-input" placeholder="${i.options.search.placeholder}">
|
||||
<i class="fa fa-times-circle wpforms-builder-dropdown-list-search-close" aria-hidden="true"></i>
|
||||
</div>`:"",n=i.options.search.enabled?"list":"";return`<div class="wpforms-builder-dropdown-list closed ${i.options.class}">
|
||||
<div class="title">${i.options.title}</div>
|
||||
${t}
|
||||
<ul class="${n}">${e.join("")}</ul>
|
||||
<div class="wpforms-no-results">${i.options.search.noResultsText}</div>
|
||||
</div>`},i.attach=function(){var e=i.generateHtml();i.$el&&i.$el.length&&i.$el.remove(),i.$el=t(e),i.$button=t(i.options.button),i.$container=i.options.container?t(i.options.container):i.$button.parent(),i.$scrollableContainer=i.options.scrollableContainer?t(i.options.scrollableContainer):null,i.options.search.enabled&&(i.searchItems=new List(i.$el[0],{valueNames:i.options.search.searchBy})),i.$container.append(i.$el),i.setPosition()},i.setPosition=function(){var e=i.$button.offset(),o=i.$container.offset(),t=i.$container.position(),n=i.$el.height(),s=i.$scrollableContainer?i.$scrollableContainer.scrollTop():0;let l=e.top-o.top-n-i.options.buttonDistance;s+t.top-n<0&&(l=e.top-o.top+i.$button.height()+i.options.buttonDistance-11,i.$el.addClass("open-down")),i.$el.css("top",l),i.options.noLeftOffset||0===i.$container.closest(".wpforms-field-option").length&&i.$el.css("left",e.left-o.left)},i.events=function(){i.$el.find("li").off().on("click",function(e){var o;"function"==typeof i.options.onSelect&&(o=t(this),i.options.search.enabled&&i.clearSearch(),i.options.onSelect(e,o.data("value"),o.text(),o,i))}),i.options.search.enabled&&(i.$el.find('input[type="search"]').on("keyup search",i.search),i.$el.find(".wpforms-builder-dropdown-list-search-close").on("click",i.clearSearch))},i.init=function(e=null){i.options.list=e||i.options.list,i.attach(),i.events(),i.$button.data("dropdown-list",i)},i.destroy=function(){i.$button.data("dropdown-list",null),i.$el.remove()},i.search=function(e){var e=e.target.value.toLowerCase(),o=i.$el.find(".wpforms-no-results");""!==e&&i.$el.find(".wpforms-builder-dropdown-list-search-close").addClass("active"),i.searchItems.search(e),o.toggle(0===i.searchItems.visibleItems.length)},i.clearSearch=function(){i.$el.find('input[type="search"]').val(""),i.$el.find(".wpforms-no-results").hide(),i.$el.find(".wpforms-builder-dropdown-list-search-close").removeClass("active"),i.searchItems.search()},i.init()}return{init(e){return new o(e)}}})((document,window,jQuery));
|
||||
@@ -0,0 +1,217 @@
|
||||
/* eslint-disable camelcase */
|
||||
/* global wpforms_builder_email_template */
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
/**
|
||||
* Script for manipulating DOM events in the "Builder" settings page.
|
||||
* This script will be accessible in the "WPForms" → "Builder" → "Notifications" tab/page.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*/
|
||||
// eslint-disable-next-line no-var
|
||||
var WPFormsBuilderEmailTemplate = window.WPFormsBuilderEmailTemplate || ( function( document, window, $, l10n ) {
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const el = {};
|
||||
|
||||
/**
|
||||
* Runtime variables.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const vars = {
|
||||
/**
|
||||
* Modal instance.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*/
|
||||
modal: null,
|
||||
|
||||
/**
|
||||
* Generic CSS class names for applying visual changes.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*/
|
||||
classNames: {
|
||||
modalBox: 'wpforms-modal-content-box',
|
||||
modalOpen: 'wpforms-email-template-modal-open',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*/
|
||||
ready() {
|
||||
app.setup();
|
||||
app.bindEvents();
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup. Prepare some variables.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*/
|
||||
setup() {
|
||||
// Cache DOM elements.
|
||||
el.$document = $( document );
|
||||
el.$body = $( 'body' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*/
|
||||
bindEvents() {
|
||||
el.$document
|
||||
.on( 'change', '.wpforms-email-template-modal-content input[type="radio"]', app.handleOnChangeTemplate )
|
||||
.on( 'click', '.wpforms-all-email-template-modal', app.handleOnOpenModal );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle the "change" event for the template radio buttons.
|
||||
* This function updates the select field based on the selected radio button.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*
|
||||
* @param {Object} event The DOM event that triggered the function.
|
||||
*/
|
||||
handleOnChangeTemplate( event ) {
|
||||
// Prevent the default action, which is to handle the change event.
|
||||
event.preventDefault();
|
||||
|
||||
// Extract the ID of the field from the element.
|
||||
const id = app.getIdFromElm( $( this ) );
|
||||
|
||||
// Get the corresponding select field.
|
||||
const $field = $( `#wpforms-panel-field-notifications-${ id }-template` );
|
||||
|
||||
// If the select field doesn't exist, no further action is needed.
|
||||
if ( ! $field.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the modal doesn't exist, no further action is needed.
|
||||
if ( ! vars.modal ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the value of the radio button that triggered the change.
|
||||
const value = $( this ).val();
|
||||
|
||||
// Update the select field with the selected value and trigger the change event.
|
||||
$field.val( value ).trigger( 'change' );
|
||||
|
||||
// Close the modal.
|
||||
vars.modal.close();
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle the "click" event for opening the modal.
|
||||
* This will open the modal with the available templates.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*/
|
||||
handleOnOpenModal() {
|
||||
// Get the email template modal template.
|
||||
const template = wp.template( 'wpforms-email-template-modal' );
|
||||
|
||||
// If the template doesn't exist, exit the function.
|
||||
if ( ! template.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the closest wrapper and select element.
|
||||
const $wrapper = $( this ).closest( '.wpforms-panel-field-email-template-wrap' );
|
||||
const $select = $wrapper.find( 'select' );
|
||||
|
||||
// Get the selected value from the select element and its ID.
|
||||
const selected = $select.val() || '';
|
||||
const id = app.getIdFromElm( $select );
|
||||
|
||||
// Extract relevant data from l10n.
|
||||
const { templates, is_pro } = l10n;
|
||||
|
||||
// Prepare the data to be passed to the template.
|
||||
const data = { templates, selected, is_pro, id };
|
||||
|
||||
// Generate the modal's content using the template and data.
|
||||
const content = template( data );
|
||||
|
||||
// Open the modal.
|
||||
vars.modal = $.confirm( {
|
||||
content,
|
||||
title: '',
|
||||
boxWidth: 800,
|
||||
contentMaxHeight: 'none',
|
||||
backgroundDismiss: true,
|
||||
smoothContent: false,
|
||||
closeIcon: true,
|
||||
buttons: false,
|
||||
// Callback function before the modal opens.
|
||||
onOpenBefore() {
|
||||
this.$body.addClass( vars.classNames.modalBox );
|
||||
el.$body.addClass( vars.classNames.modalOpen );
|
||||
},
|
||||
// Callback function when the modal is closed.
|
||||
onClose() {
|
||||
el.$body.removeClass( vars.classNames.modalOpen );
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the ID from the element.
|
||||
* This is a helper function for extracting the numeric ID from an element's ID attribute.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*
|
||||
* @param {Object} $elm jQuery object representing the element.
|
||||
*
|
||||
* @return {number} The numeric ID extracted from the element's ID attribute.
|
||||
*/
|
||||
getIdFromElm( $elm ) {
|
||||
// Get the ID attribute from the element.
|
||||
const id = $elm.attr( 'id' );
|
||||
|
||||
// If no ID attribute is found, return 0.
|
||||
if ( ! id ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Extract and parse the numeric part from the ID.
|
||||
return parseInt( id.match( /\d+/ )[ 0 ], 10 );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery, wpforms_builder_email_template ) );
|
||||
|
||||
// Initialize.
|
||||
WPFormsBuilderEmailTemplate.init();
|
||||
+1
@@ -0,0 +1 @@
|
||||
var WPFormsBuilderEmailTemplate=window.WPFormsBuilderEmailTemplate||((e,m,n)=>{let d={},s={modal:null,classNames:{modalBox:"wpforms-modal-content-box",modalOpen:"wpforms-email-template-modal-open"}},i={init(){m(i.ready)},ready(){i.setup(),i.bindEvents()},setup(){d.$document=m(e),d.$body=m("body")},bindEvents(){d.$document.on("change",'.wpforms-email-template-modal-content input[type="radio"]',i.handleOnChangeTemplate).on("click",".wpforms-all-email-template-modal",i.handleOnOpenModal)},handleOnChangeTemplate(e){e.preventDefault();var a,e=i.getIdFromElm(m(this)),e=m(`#wpforms-panel-field-notifications-${e}-template`);e.length&&s.modal&&(a=m(this).val(),e.val(a).trigger("change"),s.modal.close())},handleOnOpenModal(){var e,a,l,t,o=wp.template("wpforms-email-template-modal");o.length&&(e=(a=m(this).closest(".wpforms-panel-field-email-template-wrap").find("select")).val()||"",a=i.getIdFromElm(a),{templates:l,is_pro:t}=n,o=o({templates:l,selected:e,is_pro:t,id:a}),s.modal=m.confirm({content:o,title:"",boxWidth:800,contentMaxHeight:"none",backgroundDismiss:!0,smoothContent:!1,closeIcon:!0,buttons:!1,onOpenBefore(){this.$body.addClass(s.classNames.modalBox),d.$body.addClass(s.classNames.modalOpen)},onClose(){d.$body.removeClass(s.classNames.modalOpen)}}))},getIdFromElm(e){e=e.attr("id");return e?parseInt(e.match(/\d+/)[0],10):0}};return i})(document,(window,jQuery),wpforms_builder_email_template);WPFormsBuilderEmailTemplate.init();
|
||||
@@ -0,0 +1,236 @@
|
||||
/* global wpforms_builder, WPFormsUtils, wpf */
|
||||
|
||||
/**
|
||||
* @param wpforms_builder.add_custom_value_label
|
||||
* @param wpforms_builder.select_field
|
||||
*/
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
/**
|
||||
* Form Builder Field Map.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*/
|
||||
var WPForms = window.WPForms || {}; // eslint-disable-line no-var
|
||||
|
||||
WPForms.Admin = WPForms.Admin || {};
|
||||
WPForms.Admin.Builder = WPForms.Admin.Builder || {};
|
||||
|
||||
WPForms.Admin.Builder.FieldMap = WPForms.Admin.Builder.FieldMap || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const el = {};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* DOM is fully loaded.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*/
|
||||
ready() {
|
||||
app.setup();
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup. Prepare some variables.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*/
|
||||
setup() {
|
||||
// Cache DOM elements.
|
||||
el.$builder = $( '#wpforms-builder' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*/
|
||||
events() {
|
||||
// Field map table, update a key source.
|
||||
el.$builder.on( 'input', '.wpforms-field-map-table .key-source', function() {
|
||||
const value = $( this ).val(),
|
||||
$dest = $( this ).parent().parent().find( '.key-destination' ),
|
||||
name = $dest.data( 'name' );
|
||||
|
||||
if ( value ) {
|
||||
$dest.attr( 'name', name.replace( '{source}', value.replace( /[^0-9a-zA-Z_-]/gi, '' ) ) );
|
||||
}
|
||||
} );
|
||||
|
||||
// Field map table, delete row
|
||||
el.$builder.on( 'click', '.wpforms-field-map-table .remove', function( e ) {
|
||||
e.preventDefault();
|
||||
app.fieldMapTableDeleteRow( e, $( this ) );
|
||||
} );
|
||||
|
||||
// Field map table, Add row
|
||||
el.$builder.on( 'click', '.wpforms-field-map-table .add', function( e ) {
|
||||
e.preventDefault();
|
||||
app.fieldMapTableAddRow( e, $( this ) );
|
||||
} );
|
||||
|
||||
// Global select field mapping
|
||||
$( document ).on( 'wpformsFieldUpdate', app.fieldMapSelect );
|
||||
},
|
||||
|
||||
/**
|
||||
* Field map table - Delete row.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @since 1.6.1.2 Registered `wpformsFieldMapTableDeletedRow` trigger.
|
||||
*
|
||||
* @param {Event} e Event.
|
||||
* @param {Element} element Element.
|
||||
*/
|
||||
fieldMapTableDeleteRow( e, element ) {
|
||||
const $this = $( element ),
|
||||
$row = $this.closest( 'tr' ),
|
||||
$table = $this.closest( 'table' ),
|
||||
$block = $row.closest( '.wpforms-builder-settings-block' ),
|
||||
total = $table.find( 'tr' ).length;
|
||||
|
||||
if ( total > '1' ) {
|
||||
$row.remove();
|
||||
|
||||
el.$builder.trigger( 'wpformsFieldMapTableDeletedRow', [ $block ] );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Field map table - Add row.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @since 1.6.1.2 Registered `wpformsFieldMapTableAddedRow` trigger.
|
||||
*
|
||||
* @param {Event} e Event.
|
||||
* @param {Element} element Element.
|
||||
*/
|
||||
fieldMapTableAddRow( e, element ) {
|
||||
const $this = $( element ),
|
||||
$row = $this.closest( 'tr' ),
|
||||
$block = $row.closest( '.wpforms-builder-settings-block' ),
|
||||
choice = $row.clone().insertAfter( $row );
|
||||
|
||||
choice.find( 'input' ).val( '' );
|
||||
choice.find( 'select :selected' ).prop( 'selected', false );
|
||||
choice.find( '.key-destination' ).attr( 'name', '' );
|
||||
|
||||
el.$builder.trigger( 'wpformsFieldMapTableAddedRow', [ $block, choice ] );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update field mapped select items on form updates.
|
||||
* Use data attributes to configure field mapping:
|
||||
* - data-field-map-placeholder - A custom placeholder text shown in the select dropdown field.
|
||||
* - data-field-map-allowed - Space-separated list of allowed field types (e.g. "email textarea"). Use "all-fields" to allow all available form fields.
|
||||
* - data-field-map-allow-repeated-fields - Controls whether fields inside repeater blocks are included in the options (true/false).
|
||||
* - data-custom-value-support - When true, adds a "Custom Value" option at the end of the dropdown list.
|
||||
*
|
||||
* @since 1.2.0
|
||||
* @since 1.6.1.2 Registered `wpformsFieldSelectMapped` trigger.
|
||||
* @since 1.9.7 Removed all passed arguments.
|
||||
* @since 1.9.7 The list of fields is received via the `wpf.getFields` function.
|
||||
* @since 1.9.7 Added multiple fields support.
|
||||
*/
|
||||
fieldMapSelect() {
|
||||
const event = WPFormsUtils.triggerEvent( el.$builder, 'wpformsBeforeFieldMapSelectUpdate' );
|
||||
|
||||
// Allow callbacks on `wpformsBeforeFieldMapSelectUpdate` to cancel adding field
|
||||
// by triggering `event.preventDefault()`.
|
||||
if ( event.isDefaultPrevented() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line complexity
|
||||
$( '.wpforms-field-map-select' ).each( function() {
|
||||
const $this = $( this );
|
||||
|
||||
let placeholder = $this.data( 'field-map-placeholder' );
|
||||
|
||||
// Check if a custom placeholder was provided.
|
||||
if ( typeof placeholder === 'undefined' || ! placeholder ) {
|
||||
placeholder = wpforms_builder.select_field;
|
||||
}
|
||||
|
||||
let allowedFields = $this.data( 'field-map-allowed' );
|
||||
|
||||
// If allowed, fields are not defined, bail.
|
||||
if ( typeof allowedFields === 'undefined' || ! allowedFields ) {
|
||||
return;
|
||||
}
|
||||
|
||||
allowedFields = allowedFields.split( ' ' );
|
||||
allowedFields = $.inArray( 'all-fields', allowedFields ) >= 0 ? false : allowedFields;
|
||||
|
||||
const isAllowedRepeatedFields = Boolean( $this.data( 'field-map-allow-repeated-fields' ) );
|
||||
const selectedValue = $this.val();
|
||||
const fields = wpf.getFields( allowedFields, true, isAllowedRepeatedFields );
|
||||
|
||||
$this.empty();
|
||||
$this.append( $( '<option>', { value: '', text: placeholder } ) );
|
||||
|
||||
if ( fields && ! $.isEmptyObject( fields ) ) {
|
||||
for ( const fieldID in fields ) {
|
||||
if ( ! fields[ fieldID ]?.id ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const field = fields[ fieldID ];
|
||||
const label = wpf.sanitizeHTML( field?.label?.toString().trim() || wpforms_builder.field + ' #' + field.id );
|
||||
|
||||
$this.append( $( '<option>', { value: field.id, text: label } ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Add a "Custom Value" option if it is supported.
|
||||
const customValueSupport = $this.data( 'custom-value-support' );
|
||||
|
||||
if ( typeof customValueSupport === 'boolean' && customValueSupport ) {
|
||||
$this.append(
|
||||
$( '<option>', {
|
||||
value: 'custom_value',
|
||||
text: wpforms_builder.add_custom_value_label,
|
||||
class: 'wpforms-field-map-option-custom-value',
|
||||
} )
|
||||
);
|
||||
}
|
||||
|
||||
if ( selectedValue ) {
|
||||
$this.val( selectedValue );
|
||||
}
|
||||
|
||||
el.$builder.trigger( 'wpformsFieldSelectMapped', [ $this ] );
|
||||
} );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPForms.Admin.Builder.FieldMap.init();
|
||||
+1
@@ -0,0 +1 @@
|
||||
var WPForms=window.WPForms||{};WPForms.Admin=WPForms.Admin||{},WPForms.Admin.Builder=WPForms.Admin.Builder||{},WPForms.Admin.Builder.FieldMap=WPForms.Admin.Builder.FieldMap||((e,s)=>{let p={},l={init(){s(l.ready)},ready(){l.setup(),l.events()},setup(){p.$builder=s("#wpforms-builder")},events(){p.$builder.on("input",".wpforms-field-map-table .key-source",function(){var e=s(this).val(),l=s(this).parent().parent().find(".key-destination"),i=l.data("name");e&&l.attr("name",i.replace("{source}",e.replace(/[^0-9a-zA-Z_-]/gi,"")))}),p.$builder.on("click",".wpforms-field-map-table .remove",function(e){e.preventDefault(),l.fieldMapTableDeleteRow(e,s(this))}),p.$builder.on("click",".wpforms-field-map-table .add",function(e){e.preventDefault(),l.fieldMapTableAddRow(e,s(this))}),s(e).on("wpformsFieldUpdate",l.fieldMapSelect)},fieldMapTableDeleteRow(e,l){var l=s(l),i=l.closest("tr"),l=l.closest("table"),t=i.closest(".wpforms-builder-settings-block");"1"<l.find("tr").length&&(i.remove(),p.$builder.trigger("wpformsFieldMapTableDeletedRow",[t]))},fieldMapTableAddRow(e,l){var l=s(l).closest("tr"),i=l.closest(".wpforms-builder-settings-block"),l=l.clone().insertAfter(l);l.find("input").val(""),l.find("select :selected").prop("selected",!1),l.find(".key-destination").attr("name",""),p.$builder.trigger("wpformsFieldMapTableAddedRow",[i,l])},fieldMapSelect(){WPFormsUtils.triggerEvent(p.$builder,"wpformsBeforeFieldMapSelectUpdate").isDefaultPrevented()||s(".wpforms-field-map-select").each(function(){var e=s(this);let l=e.data("field-map-placeholder"),i=(void 0!==l&&l||(l=wpforms_builder.select_field),e.data("field-map-allowed"));if(void 0!==i&&i){i=i.split(" "),i=!(0<=s.inArray("all-fields",i))&&i;var t,d=Boolean(e.data("field-map-allow-repeated-fields")),a=e.val(),r=wpf.getFields(i,!0,d);if(e.empty(),e.append(s("<option>",{value:"",text:l})),r&&!s.isEmptyObject(r))for(var o in r)r[o]?.id&&(o=r[o],t=wpf.sanitizeHTML(o?.label?.toString().trim()||wpforms_builder.field+" #"+o.id),e.append(s("<option>",{value:o.id,text:t})));d=e.data("custom-value-support");"boolean"==typeof d&&d&&e.append(s("<option>",{value:"custom_value",text:wpforms_builder.add_custom_value_label,class:"wpforms-field-map-option-custom-value"})),a&&e.val(a),p.$builder.trigger("wpformsFieldSelectMapped",[e])}})}};return l})(document,(window,jQuery)),WPForms.Admin.Builder.FieldMap.init();
|
||||
+486
@@ -0,0 +1,486 @@
|
||||
/* global wpforms_builder, wpf, WPFormsBuilder, WPForms, md5 */
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* WPForms Internal Information Field builder functions.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*/
|
||||
var WPFormsInternalInformationField = window.WPFormsInternalInformationField || ( function( document, window, $ ) { // eslint-disable-line
|
||||
|
||||
/**
|
||||
* WPForms builder element.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @type {jQuery}
|
||||
*/
|
||||
let $builder;
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
let app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*/
|
||||
init: function() {
|
||||
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialized once the DOM is fully loaded.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*/
|
||||
ready: function() {
|
||||
|
||||
$builder = $( '#wpforms-builder' );
|
||||
|
||||
app.bindUIActionsFields();
|
||||
},
|
||||
|
||||
/**
|
||||
* Element bindings.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*/
|
||||
bindUIActionsFields: function() {
|
||||
|
||||
app.dragDisable();
|
||||
|
||||
$builder
|
||||
.on( 'wpformsFieldAdd', app.dragDisable )
|
||||
.on( 'input', '.wpforms-field-option-row-heading input[type="text"]', app.headingUpdates )
|
||||
.on( 'input', '.wpforms-field-option-row-expanded-description textarea', app.expandedDescriptionUpdates )
|
||||
.on( 'input', '.wpforms-field-option-row-cta-label input[type="text"]', app.ctaButtonLabelUpdates )
|
||||
.on( 'input', '.wpforms-field-option-row-cta-link input[type="text"]', app.ctaButtonLinkUpdates )
|
||||
.on( 'click', '.cta-button.cta-expand-description a', app.showExpandedDescription )
|
||||
.on( 'focusout', '.wpforms-field-option-row-cta-link input[type="text"]', app.validateCTAlinkField )
|
||||
.on( 'mousedown', '.wpforms-field-internal-information-checkbox', app.handleCheckboxClick )
|
||||
.on( 'wpformsDescriptionFieldUpdated', app.descriptionFieldUpdated )
|
||||
.on( 'wpformsBeforeFieldDeleteAlert', app.preventDeleteFieldAlert )
|
||||
.on( 'mouseenter', '.internal-information-not-editable .wpforms-field-delete', app.showDismissTitle );
|
||||
},
|
||||
|
||||
/**
|
||||
* Save checkbox state as a post meta.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @param {string} name Checkbox name.
|
||||
* @param {int} checked Checkbox state.
|
||||
*/
|
||||
saveInternalInformationCheckbox: function( name, checked ) {
|
||||
|
||||
$.post(
|
||||
wpforms_builder.ajax_url,
|
||||
{
|
||||
action: 'wpforms_builder_save_internal_information_checkbox',
|
||||
formId: $( '#wpforms-builder-form' ).data( 'id' ),
|
||||
name: name,
|
||||
checked: checked,
|
||||
nonce: wpforms_builder.nonce,
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Replace checkboxes.
|
||||
*
|
||||
* @since 1.7.6
|
||||
* @since 1.7.9 Added ID parameter.
|
||||
*
|
||||
* @param {string} description Expanded description.
|
||||
* @param {int} id Field ID.
|
||||
*
|
||||
* @returns {string} Expanded description with checkboxes HTML.
|
||||
*/
|
||||
replaceCheckboxes: function( description, id ) {
|
||||
|
||||
const lines = description.split( /\r?\n/ ),
|
||||
replaced = [],
|
||||
needle = '[] ';
|
||||
|
||||
let lineNumber = -1;
|
||||
|
||||
for ( let line of lines ) {
|
||||
|
||||
lineNumber++;
|
||||
line = line.trim();
|
||||
|
||||
if ( ! line.startsWith( needle ) ) {
|
||||
replaced.push( line );
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const hash = md5( line ),
|
||||
name = `iif-${id}-${hash}-${lineNumber}`;
|
||||
|
||||
line = line.replace( '[] ', `<div class="wpforms-field-internal-information-checkbox-wrap"><div class="wpforms-field-internal-information-checkbox-input"><input type="checkbox" name="${name}" value="1" class="wpforms-field-internal-information-checkbox" /></div><div class="wpforms-field-internal-information-checkbox-label">` ); line += '</div></div>';
|
||||
|
||||
replaced.push( line );
|
||||
}
|
||||
|
||||
return ( wpf.wpautop( replaced.join( '\n' ) ) ).replace( /<br \/>\n$/, '' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Do not allow field to be draggable.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*/
|
||||
dragDisable: function() {
|
||||
|
||||
WPForms.Admin.Builder.DragFields.fieldDragDisable( $( '.internal-information-not-draggable' ), false );
|
||||
},
|
||||
|
||||
/**
|
||||
* Real-time updates for "Heading" field option.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*/
|
||||
headingUpdates: function() {
|
||||
|
||||
let $this = $( this ),
|
||||
value = wpf.sanitizeHTML( $this.val() ),
|
||||
$head = $( '#wpforms-field-' + $this.parent().data( 'field-id' ) ).find( '.wpforms-field-internal-information-row-heading .heading' );
|
||||
|
||||
$head.toggle( value.length !== 0 );
|
||||
WPFormsBuilder.updateDescription( $head.find( '.text' ), value );
|
||||
},
|
||||
|
||||
/**
|
||||
* Real-time updates for "Expanded Description" field option.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*/
|
||||
expandedDescriptionUpdates: function() {
|
||||
|
||||
const $this = $( this ),
|
||||
value = wpf.sanitizeHTML( $this.val() ),
|
||||
id = $this.parent().data( 'field-id' ),
|
||||
$field = $( '#wpforms-field-' + id ),
|
||||
$wrapper = $field.find( '.internal-information-wrap' ),
|
||||
$buttonContainer = $field.find( '.wpforms-field-internal-information-row-cta-button' ),
|
||||
$options = $( '#wpforms-field-option-' + id ),
|
||||
link = $options.find( '.wpforms-field-option-row-cta-link input[type="text"]' ).val(),
|
||||
label = $options.find( '.wpforms-field-option-row-cta-label input[type="text"]' ).val().length !== 0 ? $options.find( '.wpforms-field-option-row-cta-label input[type="text"]' ).val() : wpforms_builder.empty_label,
|
||||
$expandable = $wrapper.find( '.wpforms-field-internal-information-row-expanded-description' );
|
||||
|
||||
const newLines = app.replaceCheckboxes( value, id );
|
||||
|
||||
WPFormsBuilder.updateDescription( $wrapper.find( '.expanded-description' ), newLines );
|
||||
|
||||
if ( value.length !== 0 ) { // Expanded description has content.
|
||||
if ( $expandable.hasClass( 'expanded' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update CTA button.
|
||||
$buttonContainer.html( app.notExpandedButton() );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$expandable.hide().removeClass( 'expanded' );
|
||||
|
||||
if ( link.length === 0 ) { // Expanded description does not have value and button has no link.
|
||||
$buttonContainer.html( '' );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$buttonContainer.html( app.standardCtaButton( link, label ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* Expand additional description on button click.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @param {object} event Click event.
|
||||
*/
|
||||
showExpandedDescription: function( event ) {
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
const $this = $( this ),
|
||||
id = $this.closest( '.wpforms-field-internal-information' ).data( 'field-id' ),
|
||||
$expandable = $this.closest( '.internal-information-content' ).find( '.wpforms-field-internal-information-row-expanded-description' ),
|
||||
$buttonContainer = $( '#wpforms-field-' + id ).find( '.wpforms-field-internal-information-row-cta-button' ),
|
||||
isExpanded = $expandable.hasClass( 'expanded' );
|
||||
|
||||
$expandable.toggleClass( 'expanded' );
|
||||
|
||||
if ( ! isExpanded ) {
|
||||
$expandable.slideDown( 400 );
|
||||
$buttonContainer.html( app.expandedButton() );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$expandable.slideUp( 400 );
|
||||
$buttonContainer.html( app.notExpandedButton() );
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate if the CTA Link field has correct url.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*/
|
||||
validateCTAlinkField: function() {
|
||||
|
||||
const $field = $( this ),
|
||||
url = $field.val().trim();
|
||||
|
||||
$field.val( url );
|
||||
|
||||
if ( url === '' || wpf.isURL( url ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.confirm(
|
||||
{
|
||||
title: wpforms_builder.heads_up,
|
||||
content: wpforms_builder.iif_redirect_url_field_error,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_builder.ok,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action: function() {
|
||||
$field.trigger( 'focus' );
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle checkbox checking.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @param {object} event Click event.
|
||||
*/
|
||||
handleCheckboxClick: function( event ) {
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
const $this = $( this ),
|
||||
checked = ! $this.prop( 'checked' );
|
||||
|
||||
$this.prop( 'checked', checked );
|
||||
|
||||
app.saveInternalInformationCheckbox( $this.prop( 'name' ), Number( checked ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* Replace checkboxes on description field.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @param {object} event Triggered event.
|
||||
* @param {object} data Field element and field value.
|
||||
*/
|
||||
descriptionFieldUpdated: function( event, data ) {
|
||||
|
||||
const type = $( '#wpforms-field-' + data.id ).data( 'field-type' );
|
||||
|
||||
if ( type !== 'internal-information' || data.value.length === 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
data.value = app.replaceCheckboxes( data.value, data.id );
|
||||
|
||||
WPFormsBuilder.updateDescription( data.descField, data.value );
|
||||
},
|
||||
|
||||
/**
|
||||
* Prevent delete field alert to show.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @param {object} event Triggered event.
|
||||
* @param {object} fieldData Field data.
|
||||
* @param {string} type Field type.
|
||||
*/
|
||||
preventDeleteFieldAlert: function( event, fieldData, type ) {
|
||||
|
||||
if ( type === 'internal-information' ) {
|
||||
event.preventDefault();
|
||||
WPFormsBuilder.fieldDeleteById( fieldData.id, type, 50 );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Replace Delete field button title with Dismiss.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*/
|
||||
showDismissTitle: function() {
|
||||
|
||||
$( this ).attr( 'title', wpforms_builder.iif_dismiss );
|
||||
},
|
||||
|
||||
/**
|
||||
* Real-time updates for "CTA button" link.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*/
|
||||
ctaButtonLinkUpdates() {
|
||||
|
||||
let $this = $( this ),
|
||||
id = $this.parent().data( 'field-id' ),
|
||||
$field = $( '#wpforms-field-' + id ),
|
||||
$buttonContainer = $field.find( '.wpforms-field-internal-information-row-cta-button' ),
|
||||
$expandable = $field.find( '.wpforms-field-internal-information-row-expanded-description' ),
|
||||
desc = $this.closest( '#wpforms-field-option-' + id ).find( '.wpforms-field-option-row-expanded-description textarea' ).val(),
|
||||
label = $this.closest( '#wpforms-field-option-' + id ).find( '.wpforms-field-option-row-cta-label input[type="text"]' ).val();
|
||||
|
||||
if ( desc.length !== 0 ) {
|
||||
|
||||
if ( $expandable.hasClass( 'expanded' ) ) {
|
||||
|
||||
$buttonContainer.html( app.expandedButton() );
|
||||
|
||||
return;
|
||||
}
|
||||
$buttonContainer.html( app.notExpandedButton() );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( wpf.isURL( $this.val() ) && label.length !== 0 ) {
|
||||
$buttonContainer.html( app.standardCtaButton( $this.val(), label ) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$buttonContainer.html( '' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Real-time updates for "CTA button" label.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*/
|
||||
ctaButtonLabelUpdates: function() {
|
||||
|
||||
let $this = $( this ),
|
||||
value = wpf.sanitizeHTML( $this.val() ),
|
||||
id = $this.parent().data( 'field-id' ),
|
||||
$field = $( '#wpforms-field-' + id ),
|
||||
$buttonContainer = $field.find( '.wpforms-field-internal-information-row-cta-button' ),
|
||||
$expandable = $field.find( '.wpforms-field-internal-information-row-expanded-description' ),
|
||||
desc = $this.closest( '#wpforms-field-option-' + id ).find( '.wpforms-field-option-row-expanded-description textarea' ).val(),
|
||||
link = $this.closest( '#wpforms-field-option-' + id ).find( '.wpforms-field-option-row-cta-link input[type="text"]' ).val();
|
||||
|
||||
if ( desc.length !== 0 && value.length !== 0 ) {
|
||||
if ( $expandable.hasClass( 'expanded' ) ) {
|
||||
|
||||
$buttonContainer.html( app.expandedButton() );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$buttonContainer.html( app.notExpandedButton() );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( value.length !== 0 && wpf.isURL( link ) ) {
|
||||
$buttonContainer.html( app.standardCtaButton( link, value ) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( desc.length === 0 ) {
|
||||
$buttonContainer.html( '' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Standard CTA button template.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @param {string} url Button URL.
|
||||
* @param {string} label Button label.
|
||||
*
|
||||
* @returns {string} Button HTML.
|
||||
*/
|
||||
standardCtaButton: function( url, label ) {
|
||||
|
||||
let button = `<div class="cta-button cta-link-external ">
|
||||
<a href="%url%" target="_blank" rel="noopener noreferrer">
|
||||
<span class="button-label">%label%</span>
|
||||
</a></div>`;
|
||||
|
||||
return button.replace( '%url%', wpf.sanitizeHTML( url ) ).replace( '%label%', wpf.sanitizeHTML( label ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* Not expanded button.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @returns {string} Not expanded button HTML.
|
||||
*/
|
||||
notExpandedButton: function() {
|
||||
|
||||
let button = `<div class="cta-button cta-expand-description not-expanded">
|
||||
<a href="#" target="_blank" rel="noopener noreferrer">
|
||||
<span class="button-label">%label%</span>
|
||||
<span class="icon not-expanded">
|
||||
<svg viewBox="0 0 10 7">
|
||||
<path d="M4.91016 5.90234C5.15625 6.14844 5.56641 6.14844 5.8125 5.90234L9.53125 2.18359C9.80469 1.91016 9.80469 1.5 9.53125 1.25391L8.92969 0.625C8.65625 0.378906 8.24609 0.378906 8 0.625L5.34766 3.27734L2.72266 0.625C2.47656 0.378906 2.06641 0.378906 1.79297 0.625L1.19141 1.25391C0.917969 1.5 0.917969 1.91016 1.19141 2.18359L4.91016 5.90234Z"></path>
|
||||
<path d="M4.91016 5.90234C5.15625 6.14844 5.56641 6.14844 5.8125 5.90234L9.53125 2.18359C9.80469 1.91016 9.80469 1.5 9.53125 1.25391L8.92969 0.625C8.65625 0.378906 8.24609 0.378906 8 0.625L5.34766 3.27734L2.72266 0.625C2.47656 0.378906 2.06641 0.378906 1.79297 0.625L1.19141 1.25391C0.917969 1.5 0.917969 1.91016 1.19141 2.18359L4.91016 5.90234Z"></path>
|
||||
</svg>
|
||||
</span>
|
||||
</a></div>`;
|
||||
|
||||
return button.replace( '%label%', wpforms_builder.iif_more );
|
||||
},
|
||||
|
||||
/**
|
||||
* Expanded button.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @returns {string} Expanded button HTML.
|
||||
*/
|
||||
expandedButton: function() {
|
||||
|
||||
let button = `<div class="cta-button cta-expand-description expanded">
|
||||
<a href="#" target="_blank" rel="noopener noreferrer">
|
||||
<span class="button-label">%label%</span>
|
||||
<span class="icon expanded">
|
||||
<svg viewBox="0 0 10 7">
|
||||
<path d="M5.83984 0.625C5.56641 0.378906 5.15625 0.378906 4.91016 0.625L1.19141 4.34375C0.917969 4.61719 0.917969 5.02734 1.19141 5.27344L1.79297 5.90234C2.06641 6.14844 2.47656 6.14844 2.72266 5.90234L5.375 3.25L8 5.90234C8.24609 6.14844 8.68359 6.14844 8.92969 5.90234L9.55859 5.27344C9.80469 5.02734 9.80469 4.61719 9.55859 4.34375L5.83984 0.625Z" fill="red"></path>
|
||||
</svg>
|
||||
</span>
|
||||
</a></div>`;
|
||||
|
||||
return button.replace( '%label%', wpforms_builder.close );
|
||||
},
|
||||
};
|
||||
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
WPFormsInternalInformationField.init();
|
||||
Vendored
Executable
+21
File diff suppressed because one or more lines are too long
@@ -0,0 +1,317 @@
|
||||
/* global wpf */
|
||||
|
||||
/**
|
||||
* Form Builder Field Numbers module.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*/
|
||||
var WPForms = window.WPForms || {}; // eslint-disable-line no-var
|
||||
|
||||
WPForms.Admin = WPForms.Admin || {};
|
||||
WPForms.Admin.Builder = WPForms.Admin.Builder || {};
|
||||
|
||||
WPForms.Admin.Builder.FieldNumbers = WPForms.Admin.Builder.FieldNumbers || ( function( document, window, $ ) { // eslint-disable-line
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* WPForms builder element.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*
|
||||
* @type {jQuery}
|
||||
*/
|
||||
$builder: null,
|
||||
|
||||
/**
|
||||
* Track if a tag was clicked recently.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
tagClicked: false,
|
||||
|
||||
/**
|
||||
* Initialize the application.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the DOM is fully loaded.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*/
|
||||
ready() {
|
||||
app.$builder = $( '#wpforms-builder' );
|
||||
app.numbersEvents();
|
||||
},
|
||||
|
||||
/**
|
||||
* Binds separate events for min, max, and default value inputs.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*/
|
||||
numbersEvents() {
|
||||
app.$builder.on(
|
||||
'change',
|
||||
'.wpforms-field-option-number .wpforms-numbers-min',
|
||||
app.onChangeNumbersMin
|
||||
);
|
||||
|
||||
app.$builder.on(
|
||||
'change',
|
||||
'.wpforms-field-option-number .wpforms-numbers-max',
|
||||
app.onChangeNumbersMax
|
||||
);
|
||||
|
||||
app.$builder.on(
|
||||
'input',
|
||||
'.wpforms-field-option-number .wpforms-field-option-row-default_value .wpforms-smart-tags-widget-original',
|
||||
_.debounce( app.onChangeNumbersDefaultValue, 500 )
|
||||
);
|
||||
|
||||
app.$builder.on(
|
||||
'click',
|
||||
'.wpforms-smart-tags-widget .tag',
|
||||
app.smartTagClickTracking
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Track clicks on the smart tag bricks.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*/
|
||||
smartTagClickTracking() {
|
||||
app.tagClicked = true;
|
||||
|
||||
// Reset the flag after a short delay.
|
||||
setTimeout( () => {
|
||||
app.tagClicked = false;
|
||||
}, 200 );
|
||||
},
|
||||
|
||||
/**
|
||||
* Parses the numeric value of a field, returning null if invalid or empty.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*
|
||||
* @param {jQuery} $field The jQuery object for the input field.
|
||||
*
|
||||
* @return {number|null} The parsed numeric value or null.
|
||||
*/
|
||||
parseFieldValue( $field ) {
|
||||
if ( ! $field.length || $field.val() === '' ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const value = parseFloat( $field.val() );
|
||||
|
||||
return isNaN( value ) ? null : value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if the min value is greater than the max value.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*
|
||||
* @param {jQuery} $minField jQuery object for the min input field.
|
||||
* @param {jQuery} $maxField jQuery object for the max input field.
|
||||
*
|
||||
* @return {boolean} True if min is greater than max, otherwise false.
|
||||
*/
|
||||
isInvalidMinMaxRange( $minField, $maxField ) {
|
||||
const min = app.parseFieldValue( $minField ),
|
||||
max = app.parseFieldValue( $maxField );
|
||||
|
||||
return min !== null && max !== null && min > max;
|
||||
},
|
||||
|
||||
/**
|
||||
* Synchronizes the min attribute on the max field.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*
|
||||
* @param {jQuery} $minField jQuery object for the min input field.
|
||||
* @param {jQuery} $maxField jQuery object for the max input field.
|
||||
*/
|
||||
syncNumberMinAttribute( $minField, $maxField ) {
|
||||
$maxField.attr( 'min', app.parseFieldValue( $minField ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* Synchronizes the max attribute on the min field.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*
|
||||
* @param {jQuery} $minField jQuery object for the min input field.
|
||||
* @param {jQuery} $maxField jQuery object for the max input field.
|
||||
*/
|
||||
syncNumberMaxAttribute( $minField, $maxField ) {
|
||||
$minField.attr( 'max', app.parseFieldValue( $maxField ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* Adjusts the target field's value to match the source field's value.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*
|
||||
* @param {jQuery} $sourceField jQuery object for the field with the value to copy.
|
||||
* @param {jQuery} $targetField jQuery object for the field to update.
|
||||
*/
|
||||
adjustValue( $sourceField, $targetField ) {
|
||||
$targetField.val( app.parseFieldValue( $sourceField ) ).trigger( 'input' ).trigger( 'wpformsSmartTagsInputSync' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the 'input' event for the min field, ensuring correct min <= max and default value.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*
|
||||
* @param {Event} event The input event object.
|
||||
*/
|
||||
onChangeNumbersMin( event ) {
|
||||
const $minField = $( event.target ),
|
||||
$container = $minField.closest( '.wpforms-field-option-group' ),
|
||||
$maxField = $container.find( '.wpforms-numbers-max' ),
|
||||
$defaultValueField = $container.find( '.wpforms-field-option-row-default_value input.wpforms-smart-tags-widget-original' );
|
||||
|
||||
if ( app.isInvalidMinMaxRange( $minField, $maxField ) ) {
|
||||
app.adjustValue( $maxField, $minField );
|
||||
}
|
||||
|
||||
if ( app.isNeedAdjustDefaultValueByMinValue( $defaultValueField, $minField ) ) {
|
||||
app.adjustValue( $minField, $defaultValueField );
|
||||
}
|
||||
|
||||
app.syncNumberMinAttribute( $minField, $maxField );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the 'change' event for the max field, ensuring correct min <= max and default value.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*
|
||||
* @param {Event} event The change event object.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
onChangeNumbersMax( event ) {
|
||||
const $maxField = $( event.target ),
|
||||
$container = $maxField.closest( '.wpforms-field-option-group' ),
|
||||
$minField = $container.find( '.wpforms-numbers-min' ),
|
||||
$defaultValueField = $container.find( '.wpforms-field-option-row-default_value input.wpforms-smart-tags-widget-original' );
|
||||
|
||||
if ( app.isInvalidMinMaxRange( $minField, $maxField ) ) {
|
||||
app.adjustValue( $minField, $maxField );
|
||||
}
|
||||
|
||||
if ( app.isNeedAdjustDefaultValueByMaxValue( $defaultValueField, $maxField ) ) {
|
||||
app.adjustValue( $maxField, $defaultValueField );
|
||||
}
|
||||
|
||||
app.syncNumberMaxAttribute( $minField, $maxField );
|
||||
},
|
||||
|
||||
/**
|
||||
* Normalize a float value of the input field by replacing commas with dots.
|
||||
* If the normalized value differs from the original,
|
||||
* the input field will be updated and the 'input' event will be triggered.
|
||||
* Non-numeric values are ignored and remain unchanged.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*
|
||||
* @param {jQuery} $field The input field to normalize.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
normalizeFloatValue( $field ) {
|
||||
const value = $field.val(),
|
||||
valueWithoutComma = value.replace( ',', '.' );
|
||||
|
||||
if ( wpf.isNumber( valueWithoutComma ) && value !== parseFloat( value ).toString() ) {
|
||||
$field.val( parseFloat( valueWithoutComma ) ).trigger( 'input' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the default value is below the current min value.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*
|
||||
* @param {jQuery} $defaultValueField jQuery object for the default value input.
|
||||
* @param {jQuery} $minField jQuery object for the min input field.
|
||||
*
|
||||
* @return {boolean} True if default value is less than min, otherwise false.
|
||||
*/
|
||||
isNeedAdjustDefaultValueByMinValue( $defaultValueField, $minField ) {
|
||||
const defaultValue = app.parseFieldValue( $defaultValueField ),
|
||||
min = app.parseFieldValue( $minField );
|
||||
|
||||
return wpf.isNumber( defaultValue ) && min !== null && defaultValue < min;
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the default value is above the current max value.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*
|
||||
* @param {jQuery} $defaultValueField jQuery object for the default value input.
|
||||
* @param {jQuery} $maxField jQuery object for the max input field.
|
||||
*
|
||||
* @return {boolean} True if default value is greater than max, otherwise false.
|
||||
*/
|
||||
isNeedAdjustDefaultValueByMaxValue( $defaultValueField, $maxField ) {
|
||||
const defaultValue = app.parseFieldValue( $defaultValueField ),
|
||||
max = app.parseFieldValue( $maxField );
|
||||
|
||||
return wpf.isNumber( defaultValue ) && max !== null && defaultValue > max;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the 'change' event for the default value field, keeping it in range.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*
|
||||
* @param {Event} event The change event object.
|
||||
*/
|
||||
onChangeNumbersDefaultValue( event ) {
|
||||
if (
|
||||
app.tagClicked || // Tag was recently clicked to prevent unnecessary updates.
|
||||
event.handleObj?.type === 'focusout' // Event was triggered when editable tag was changed.
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $defaultValueField = $( event.target );
|
||||
const $container = $defaultValueField.closest( '.wpforms-field-option-group' );
|
||||
const $minField = $container.find( '.wpforms-numbers-min' );
|
||||
const $maxField = $container.find( '.wpforms-numbers-max' );
|
||||
|
||||
app.normalizeFloatValue( $defaultValueField );
|
||||
|
||||
if ( app.isNeedAdjustDefaultValueByMinValue( $defaultValueField, $minField ) ) {
|
||||
app.adjustValue( $minField, $defaultValueField );
|
||||
}
|
||||
|
||||
if ( app.isNeedAdjustDefaultValueByMaxValue( $defaultValueField, $maxField ) ) {
|
||||
app.adjustValue( $maxField, $defaultValueField );
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
WPForms.Admin.Builder.FieldNumbers.init();
|
||||
+1
@@ -0,0 +1 @@
|
||||
var WPForms=window.WPForms||{};WPForms.Admin=WPForms.Admin||{},WPForms.Admin.Builder=WPForms.Admin.Builder||{},WPForms.Admin.Builder.FieldNumbers=WPForms.Admin.Builder.FieldNumbers||(u=>{let i={$builder:null,tagClicked:!1,init(){u(i.ready)},ready(){i.$builder=u("#wpforms-builder"),i.numbersEvents()},numbersEvents(){i.$builder.on("change",".wpforms-field-option-number .wpforms-numbers-min",i.onChangeNumbersMin),i.$builder.on("change",".wpforms-field-option-number .wpforms-numbers-max",i.onChangeNumbersMax),i.$builder.on("input",".wpforms-field-option-number .wpforms-field-option-row-default_value .wpforms-smart-tags-widget-original",_.debounce(i.onChangeNumbersDefaultValue,500)),i.$builder.on("click",".wpforms-smart-tags-widget .tag",i.smartTagClickTracking)},smartTagClickTracking(){i.tagClicked=!0,setTimeout(()=>{i.tagClicked=!1},200)},parseFieldValue(e){return!e.length||""===e.val()||(e=parseFloat(e.val()),isNaN(e))?null:e},isInvalidMinMaxRange(e,a){e=i.parseFieldValue(e),a=i.parseFieldValue(a);return null!==e&&null!==a&&a<e},syncNumberMinAttribute(e,a){a.attr("min",i.parseFieldValue(e))},syncNumberMaxAttribute(e,a){e.attr("max",i.parseFieldValue(a))},adjustValue(e,a){a.val(i.parseFieldValue(e)).trigger("input").trigger("wpformsSmartTagsInputSync")},onChangeNumbersMin(e){var e=u(e.target),a=e.closest(".wpforms-field-option-group"),r=a.find(".wpforms-numbers-max"),a=a.find(".wpforms-field-option-row-default_value input.wpforms-smart-tags-widget-original");i.isInvalidMinMaxRange(e,r)&&i.adjustValue(r,e),i.isNeedAdjustDefaultValueByMinValue(a,e)&&i.adjustValue(e,a),i.syncNumberMinAttribute(e,r)},onChangeNumbersMax(e){var e=u(e.target),a=e.closest(".wpforms-field-option-group"),r=a.find(".wpforms-numbers-min"),a=a.find(".wpforms-field-option-row-default_value input.wpforms-smart-tags-widget-original");i.isInvalidMinMaxRange(r,e)&&i.adjustValue(r,e),i.isNeedAdjustDefaultValueByMaxValue(a,e)&&i.adjustValue(e,a),i.syncNumberMaxAttribute(r,e)},normalizeFloatValue(e){var a=e.val(),r=a.replace(",",".");wpf.isNumber(r)&&a!==parseFloat(a).toString()&&e.val(parseFloat(r)).trigger("input")},isNeedAdjustDefaultValueByMinValue(e,a){e=i.parseFieldValue(e),a=i.parseFieldValue(a);return wpf.isNumber(e)&&null!==a&&e<a},isNeedAdjustDefaultValueByMaxValue(e,a){e=i.parseFieldValue(e),a=i.parseFieldValue(a);return wpf.isNumber(e)&&null!==a&&a<e},onChangeNumbersDefaultValue(e){var a,r;i.tagClicked||"focusout"===e.handleObj?.type||(a=(r=(e=u(e.target)).closest(".wpforms-field-option-group")).find(".wpforms-numbers-min"),r=r.find(".wpforms-numbers-max"),i.normalizeFloatValue(e),i.isNeedAdjustDefaultValueByMinValue(e,a)&&i.adjustValue(a,e),i.isNeedAdjustDefaultValueByMaxValue(e,r)&&i.adjustValue(r,e))}};return i})((document,window,jQuery)),WPForms.Admin.Builder.FieldNumbers.init();
|
||||
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* WPForms Rating Field Builder Script
|
||||
*
|
||||
* @since 1.9.8
|
||||
*/
|
||||
var WPForms = window.WPForms || {}; // eslint-disable-line no-var
|
||||
|
||||
WPForms.Admin = WPForms.Admin || {};
|
||||
WPForms.Admin.Builder = WPForms.Admin.Builder || {};
|
||||
|
||||
WPForms.Admin.Builder.FieldRating = WPForms.Admin.Builder.FieldRating || ( function( document, window, $ ) { // eslint-disable-line
|
||||
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Initialize the application.
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the DOM is fully loaded.
|
||||
*/
|
||||
ready() {
|
||||
$( document )
|
||||
.on( 'input', '.wpforms-field-option-row-lowest_label input', app.updateLowestLabel )
|
||||
.on( 'input', '.wpforms-field-option-row-highest_label input', app.updateHighestLabel )
|
||||
.on( 'change', '.wpforms-field-option-row-label_position select', app.updateLabelPosition );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the lowest label in the preview when the input changes.
|
||||
*
|
||||
* @since 1.9.8
|
||||
*
|
||||
* @param {Event} event The input event.
|
||||
*/
|
||||
updateLowestLabel( event ) {
|
||||
app.updateLabel( event, 'lowest' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the highest label in the preview when the input changes.
|
||||
*
|
||||
* @since 1.9.8
|
||||
*
|
||||
* @param {Event} event The input event.
|
||||
*/
|
||||
updateHighestLabel( event ) {
|
||||
app.updateLabel( event, 'highest' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the label in the preview based on the input value.
|
||||
*
|
||||
* @since 1.9.8
|
||||
*
|
||||
* @param {Event} event The input event.
|
||||
* @param {string} type The type of label being updated ('lowest' or 'highest').
|
||||
*/
|
||||
updateLabel( event, type ) {
|
||||
const $input = $( event.target ),
|
||||
label = $input.val(),
|
||||
$inputContainer = $input.closest( `.wpforms-field-option-row-${ type }_label` ),
|
||||
fieldId = $inputContainer.data( 'field-id' ),
|
||||
$previewField = $( `#wpforms-field-${ fieldId }` ),
|
||||
$previewLabel = $previewField.find( `.wpforms-rating-field-${ type }-label` );
|
||||
|
||||
// Update the label in the preview.
|
||||
$previewLabel.text( label );
|
||||
|
||||
// Show or hide the labels container based on whether any labels are set.
|
||||
app.toggleLabelsVisibility( $previewField );
|
||||
},
|
||||
|
||||
/**
|
||||
* Show or hide the labels container based on whether any labels are set.
|
||||
*
|
||||
* @since 1.9.8
|
||||
*
|
||||
* @param {jQuery} $previewField The jQuery object representing the preview field.
|
||||
*/
|
||||
toggleLabelsVisibility( $previewField ) {
|
||||
const labelsContainer = $previewField.find( '.wpforms-rating-field-labels' ),
|
||||
labels = labelsContainer.find( '.wpforms-sub-label' );
|
||||
|
||||
const labelsArray = labels.map( ( _, el ) => $( el ).text() ).get(),
|
||||
filteredLabels = labelsArray.filter( ( ratingLabel ) => ratingLabel.trim() !== '' );
|
||||
|
||||
labelsContainer.toggleClass( 'wpforms-hidden', filteredLabels.length === 0 );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the label position in the preview when the select changes.
|
||||
*
|
||||
* @since 1.9.8
|
||||
*
|
||||
* @param {Event} event The change event.
|
||||
*/
|
||||
updateLabelPosition( event ) {
|
||||
const $select = $( event.target ),
|
||||
labelPosition = $select.val(),
|
||||
$inputContainer = $select.closest( '.wpforms-field-option-row-label_position' ),
|
||||
fieldId = $inputContainer.data( 'field-id' ),
|
||||
$previewField = $( `#wpforms-field-${ fieldId }` );
|
||||
|
||||
// Remove existing label position classes.
|
||||
$previewField.find( '.wpforms-rating-field-labels' ).toggleClass( 'wpforms-rating-field-labels-position-above', labelPosition === 'above' );
|
||||
},
|
||||
};
|
||||
|
||||
return app;
|
||||
}( document, window, jQuery ) ); // eslint-disable-line no-undef
|
||||
|
||||
// Initialize the application.
|
||||
WPForms.Admin.Builder.FieldRating.init();
|
||||
+1
@@ -0,0 +1 @@
|
||||
var WPForms=window.WPForms||{};WPForms.Admin=WPForms.Admin||{},WPForms.Admin.Builder=WPForms.Admin.Builder||{},WPForms.Admin.Builder.FieldRating=WPForms.Admin.Builder.FieldRating||((e,t)=>{let o={init(){t(o.ready)},ready(){t(e).on("input",".wpforms-field-option-row-lowest_label input",o.updateLowestLabel).on("input",".wpforms-field-option-row-highest_label input",o.updateHighestLabel).on("change",".wpforms-field-option-row-label_position select",o.updateLabelPosition)},updateLowestLabel(e){o.updateLabel(e,"lowest")},updateHighestLabel(e){o.updateLabel(e,"highest")},updateLabel(e,i){var e=t(e.target),l=e.val(),e=e.closest(`.wpforms-field-option-row-${i}_label`).data("field-id"),e=t("#wpforms-field-"+e);e.find(`.wpforms-rating-field-${i}-label`).text(l),o.toggleLabelsVisibility(e)},toggleLabelsVisibility(e){var e=e.find(".wpforms-rating-field-labels"),i=e.find(".wpforms-sub-label").map((e,i)=>t(i).text()).get().filter(e=>""!==e.trim());e.toggleClass("wpforms-hidden",0===i.length)},updateLabelPosition(e){var e=t(e.target),i=e.val(),e=e.closest(".wpforms-field-option-row-label_position").data("field-id");t("#wpforms-field-"+e).find(".wpforms-rating-field-labels").toggleClass("wpforms-rating-field-labels-position-above","above"===i)}};return o})(document,(window,jQuery)),WPForms.Admin.Builder.FieldRating.init();
|
||||
@@ -0,0 +1,788 @@
|
||||
/* global List, wpforms_form_templates, wpforms_addons, wpf, WPFormsUtils */
|
||||
|
||||
/**
|
||||
* @param wpforms_form_templates.admin_nonce
|
||||
* @param wpforms_form_templates.delete_template
|
||||
* @param wpforms_form_templates.delete_template_content
|
||||
* @param wpforms_form_templates.delete_template_title
|
||||
* @param wpforms_form_templates.template_addon_activate
|
||||
* @param wpforms_form_templates.template_addon_prompt
|
||||
* @param wpforms_form_templates.template_addons_error
|
||||
* @param wpforms_form_templates.template_addons_prompt
|
||||
* @param wpforms_form_templates.use_template
|
||||
*/
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
/**
|
||||
* Form Templates function.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
var WPFormsFormTemplates = window.WPFormsFormTemplates || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Runtime variables.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const vars = {};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
$( window ).on( 'load', function() {
|
||||
// in the case of jQuery 3.+ we need to wait for the `ready` event first.
|
||||
if ( typeof $.ready.then === 'function' ) {
|
||||
$.ready.then( app.load );
|
||||
} else {
|
||||
app.load();
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
ready() {
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Window load.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
load() {
|
||||
app.showUpgradeBanner();
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup. Prepare some variables.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
setup() {
|
||||
// Trigger event before initializing the template list.
|
||||
WPFormsUtils.triggerEvent( $( document ), 'wpformsSetupPanelBeforeInitTemplatesList' );
|
||||
|
||||
// Template list object.
|
||||
vars.templateList = new List( 'wpforms-setup-templates-list', {
|
||||
valueNames: [
|
||||
'wpforms-template-name',
|
||||
'wpforms-template-desc',
|
||||
{
|
||||
name: 'fields',
|
||||
attr: 'data-fields',
|
||||
},
|
||||
{
|
||||
name: 'slug',
|
||||
attr: 'data-slug',
|
||||
},
|
||||
{
|
||||
name: 'categories',
|
||||
attr: 'data-categories',
|
||||
},
|
||||
{
|
||||
name: 'subcategories',
|
||||
attr: 'data-subcategories',
|
||||
},
|
||||
{
|
||||
name: 'has-access',
|
||||
attr: 'data-has-access',
|
||||
},
|
||||
{
|
||||
name: 'favorite',
|
||||
attr: 'data-favorite',
|
||||
},
|
||||
],
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
events() {
|
||||
$( document )
|
||||
.on( 'click', '#wpforms-setup-templates-list .wpforms-template-favorite i', app.selectFavorite )
|
||||
.on( 'click', '#wpforms-setup-templates-list .wpforms-template-remove i', app.removeTemplate );
|
||||
},
|
||||
|
||||
/**
|
||||
* Select Favorite Templates.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
// eslint-disable-next-line max-lines-per-function
|
||||
selectFavorite() {
|
||||
const $heartIcon = $( this ),
|
||||
favorite = $heartIcon.hasClass( 'fa-heart-o' ),
|
||||
$favorite = $heartIcon.closest( '.wpforms-template-favorite' ),
|
||||
$template = $heartIcon.closest( '.wpforms-template' ),
|
||||
$templateName = $template.find( '.wpforms-template-name' ),
|
||||
templateSlug = $template.find( '.wpforms-template-select' ).data( 'slug' ),
|
||||
$favoritesCategory = $( '.wpforms-setup-templates-categories' ).find( '[data-category=\'favorites\']' ),
|
||||
$favoritesCount = $favoritesCategory.find( 'span' ),
|
||||
data = {
|
||||
action: 'wpforms_templates_favorite',
|
||||
slug: templateSlug,
|
||||
favorite,
|
||||
nonce: wpforms_form_templates.nonce,
|
||||
};
|
||||
|
||||
let favoritesCount = parseInt( $favoritesCount.html(), 10 );
|
||||
|
||||
const item = vars.templateList.get( 'slug', templateSlug )[ 0 ],
|
||||
values = item.values();
|
||||
|
||||
const toggleHeartIcon = function() {
|
||||
$favorite.find( '.fa-heart-o' ).toggleClass( 'wpforms-hidden', values.favorite );
|
||||
$favorite.find( '.fa-heart' ).toggleClass( 'wpforms-hidden', ! values.favorite );
|
||||
};
|
||||
|
||||
const unMarkFavorite = function() {
|
||||
values.favorite = false;
|
||||
favoritesCount = favoritesCount - 1;
|
||||
|
||||
item.values( values );
|
||||
|
||||
toggleHeartIcon();
|
||||
$templateName.data( 'data-favorite', 0 );
|
||||
$favoritesCount.html( favoritesCount );
|
||||
|
||||
app.maybeHideFavoritesCategory();
|
||||
};
|
||||
|
||||
const markFavorite = function() {
|
||||
values.favorite = true;
|
||||
favoritesCount = favoritesCount + 1;
|
||||
|
||||
item.values( values );
|
||||
|
||||
toggleHeartIcon();
|
||||
$templateName.data( 'data-favorite', 1 );
|
||||
$favoritesCount.html( favoritesCount );
|
||||
|
||||
app.maybeHideFavoritesCategory();
|
||||
};
|
||||
|
||||
$.post( wpforms_form_templates.ajaxurl, data, function( res ) {
|
||||
if ( ! res.success ) {
|
||||
if ( favorite ) {
|
||||
unMarkFavorite();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
markFavorite();
|
||||
}
|
||||
} );
|
||||
|
||||
if ( favorite ) {
|
||||
markFavorite();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
unMarkFavorite();
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove Template.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
removeTemplate() {
|
||||
const $trashIcon = $( this ),
|
||||
$template = $trashIcon.closest( '.wpforms-template-remove' ),
|
||||
$templateId = $template.data( 'template' );
|
||||
|
||||
$.alert( {
|
||||
title: wpforms_form_templates.delete_template_title,
|
||||
content: wpforms_form_templates.delete_template_content,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'red',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_form_templates.delete_template,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action() {
|
||||
app.removeUserTemplate( $templateId );
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_form_templates.cancel,
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove User Template.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*
|
||||
* @param {number} templateId Template ID.
|
||||
*/
|
||||
removeUserTemplate( templateId ) {
|
||||
vars.templateList.remove( 'slug', 'wpforms-user-template-' + templateId );
|
||||
|
||||
$.post( wpforms_form_templates.ajaxurl, {
|
||||
action: 'wpforms_user_template_remove',
|
||||
template: templateId,
|
||||
nonce: wpforms_form_templates.nonce,
|
||||
}, function( res ) {
|
||||
if ( res.success ) {
|
||||
$( '#wpforms-template-wpforms-user-template-' + templateId ).remove();
|
||||
|
||||
app.updateCategoryCount( 'all' );
|
||||
app.updateCategoryCount( 'user' );
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update category count.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*
|
||||
* @param {string} category Category name.
|
||||
*/
|
||||
updateCategoryCount( category ) {
|
||||
const categoriesList = $( '.wpforms-setup-templates-categories' ),
|
||||
$category = categoriesList.find( `[data-category='${ category }']` ),
|
||||
$count = $category.find( 'span' ),
|
||||
count = parseInt( $count.html(), 10 );
|
||||
|
||||
$count.html( count - 1 );
|
||||
$category.data( 'count', count - 1 );
|
||||
|
||||
if ( count - 1 === 0 && category === 'user' && $category.hasClass( 'active' ) ) {
|
||||
$( '.wpforms-user-templates-empty-state' ).removeClass( 'wpforms-hidden' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Maybe hide favorites category if there are no templates.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
maybeHideFavoritesCategory() {
|
||||
const $categoriesList = $( '.wpforms-setup-templates-categories' ),
|
||||
$favoritesCategory = $categoriesList.find( '[data-category=\'favorites\']' ),
|
||||
favoritesCount = parseInt( $favoritesCategory.find( 'span' ).html(), 10 );
|
||||
|
||||
$favoritesCategory.toggleClass( 'wpforms-hidden', ! favoritesCount );
|
||||
|
||||
if ( $favoritesCategory.hasClass( 'active' ) ) {
|
||||
if ( ! favoritesCount ) {
|
||||
$categoriesList.find( '[data-category=\'all\']' ).trigger( 'click' );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$favoritesCategory.trigger( 'click' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Search template callback.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
searchTemplate() {
|
||||
app.performSearch( $( this ).val() );
|
||||
app.showUpgradeBanner();
|
||||
},
|
||||
|
||||
/**
|
||||
* Perform search value.
|
||||
*
|
||||
* @since 1.7.7.2
|
||||
*
|
||||
* @param {string} query Value to search.
|
||||
*/
|
||||
performSearch( query ) {
|
||||
const searchResult = vars.templateList.search( query, [ 'name' ], function( searchString ) {
|
||||
for ( let index = 0, length = vars.templateList.items.length; index < length; index++ ) {
|
||||
const values = vars.templateList.items[ index ].values();
|
||||
const templateName = values[ 'wpforms-template-name' ].toLowerCase();
|
||||
const templateDesc = values[ 'wpforms-template-desc' ].toLowerCase();
|
||||
const fields = values.fields.toLowerCase();
|
||||
const searchRegex = new RegExp( searchString );
|
||||
|
||||
vars.templateList.items[ index ].found = searchRegex.test( templateName ) || searchRegex.test( templateDesc ) || searchRegex.test( fields );
|
||||
}
|
||||
} );
|
||||
|
||||
$( '.wpforms-templates-no-results' ).toggle( ! searchResult.length );
|
||||
},
|
||||
|
||||
/**
|
||||
* Select subcategory.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
*/
|
||||
selectSubCategory( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
const $item = $( this );
|
||||
const $activeCategory = $item.parent( 'ul' ).parent( 'li' ).parent( 'ul' ).children( 'li.active' );
|
||||
const $activeSubcategory = $( '.wpforms-setup-templates-subcategories li.active' );
|
||||
const subcategory = $item.data( 'subcategory' );
|
||||
const category = $item.parents( 'li' ).data( 'category' );
|
||||
const searchQuery = $( '#wpforms-setup-template-search' ).val();
|
||||
|
||||
// Clear active class from the parent category and current subcategory.
|
||||
$activeSubcategory.removeClass( 'active' );
|
||||
$activeCategory.removeClass( 'active' );
|
||||
|
||||
// Add active class to the parent category and current subcategory.
|
||||
$item.parents( 'li' ).addClass( 'active' );
|
||||
$item.addClass( 'active' );
|
||||
|
||||
vars.templateList.filter( function( item ) {
|
||||
return category === 'all' || ( item.values().categories.split( ',' ).indexOf( category ) > -1 && item.values().subcategories.split( ',' ).indexOf( subcategory ) > -1 );
|
||||
} );
|
||||
|
||||
if ( searchQuery !== '' ) {
|
||||
app.performSearch( searchQuery );
|
||||
}
|
||||
|
||||
app.showUpgradeBanner();
|
||||
},
|
||||
|
||||
/**
|
||||
* Select category.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
*/
|
||||
selectCategory( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
const $item = $( this ).parent(),
|
||||
$active = $item.closest( 'ul' ).find( '.active' ),
|
||||
category = $item.data( 'category' ),
|
||||
count = $item.data( 'count' ),
|
||||
searchQuery = $( '#wpforms-setup-template-search' ).val();
|
||||
|
||||
$active.removeClass( 'active' );
|
||||
$item.addClass( 'active opened' );
|
||||
|
||||
vars.templateList.filter( function( item ) {
|
||||
if ( category === 'available' ) {
|
||||
return item.values()[ 'has-access' ];
|
||||
}
|
||||
|
||||
if ( category === 'favorites' ) {
|
||||
return item.values().favorite;
|
||||
}
|
||||
|
||||
return category === 'all' || item.values().categories.split( ',' ).indexOf( category ) > -1;
|
||||
} );
|
||||
|
||||
// Display/hide User Templates empty state message.
|
||||
$( '.wpforms-user-templates-empty-state' ).toggleClass( 'wpforms-hidden', category !== 'user' || count !== 0 );
|
||||
|
||||
if ( searchQuery !== '' ) {
|
||||
app.performSearch( searchQuery );
|
||||
}
|
||||
|
||||
app.showUpgradeBanner();
|
||||
},
|
||||
|
||||
/**
|
||||
* Show/hide the subcategory list by clicking on the chevron icon.
|
||||
*
|
||||
* @since 1.8.7
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
*/
|
||||
toggleSubcategoriesList( e ) {
|
||||
e.stopPropagation();
|
||||
|
||||
const $item = $( this ).parent().parent();
|
||||
|
||||
$item.toggleClass( 'opened' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Cancel button click routine.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
selectTemplateCancel( ) {
|
||||
const $template = $( '#wpforms-setup-templates-list' ).find( '.wpforms-template.active' ),
|
||||
$button = $template.find( '.wpforms-template-select' );
|
||||
|
||||
$template.removeClass( 'active' );
|
||||
$button.html( $button.data( 'labelOriginal' ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* Show upgrade banner if a license type is less than Pro.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
showUpgradeBanner() {
|
||||
if ( ! $( '#tmpl-wpforms-templates-upgrade-banner' ).length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const template = wp.template( 'wpforms-templates-upgrade-banner' );
|
||||
|
||||
if ( ! template ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $templates = $( '#wpforms-setup-templates-list .wpforms-template' );
|
||||
|
||||
if ( $templates.length > 5 ) {
|
||||
$templates.eq( 5 ).after( template() );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$templates.last().after( template() );
|
||||
},
|
||||
|
||||
/**
|
||||
* Select template.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param {string} formName Name of the form.
|
||||
* @param {string} template Template slug.
|
||||
* @param {jQuery} $button Use a template button object.
|
||||
* @param {Function} callback The function to set the template.
|
||||
*/
|
||||
selectTemplateProcess( formName, template, $button, callback ) {
|
||||
if ( $button.data( 'addons' ) ) {
|
||||
app.addonsModal( formName, template, $button, callback );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
callback( formName, template );
|
||||
},
|
||||
|
||||
/**
|
||||
* Open required addons alert.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param {string} formName Name of the form.
|
||||
* @param {string} template Template slug.
|
||||
* @param {jQuery} $button Use a template button object.
|
||||
* @param {Function} callback The function to set the template.
|
||||
*/
|
||||
addonsModal( formName, template, $button, callback ) {
|
||||
const templateName = $button.data( 'template-name-raw' );
|
||||
const addonsNames = $button.data( 'addons-names' );
|
||||
const addonsSlugs = $button.data( 'addons' );
|
||||
const installedSlugs = $button.data( 'installed' );
|
||||
const addons = addonsSlugs.split( ',' );
|
||||
|
||||
let prompt;
|
||||
|
||||
switch ( app.action( addons, installedSlugs ) ) {
|
||||
case 'multiple':
|
||||
prompt = wpforms_form_templates.template_addons_prompt;
|
||||
break;
|
||||
case 'activate':
|
||||
prompt = wpforms_form_templates.template_addon_activate;
|
||||
break;
|
||||
case 'install':
|
||||
prompt = wpforms_form_templates.template_addon_prompt;
|
||||
break;
|
||||
default:
|
||||
prompt = wpforms_form_templates.template_addons_prompt;
|
||||
break;
|
||||
}
|
||||
|
||||
prompt = prompt.replace( /%template%/g, templateName ).replace( /%addons%/g, addonsNames );
|
||||
|
||||
if ( ! addons.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! wpforms_form_templates.can_install_addons ) {
|
||||
app.userCannotInstallAddonsModal( prompt );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
app.userCanInstallAddonsModal( formName, template, addons, prompt, callback, installedSlugs );
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the template addon alert for admins.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param {string} formName Name of the form.
|
||||
* @param {string} template Template slug.
|
||||
* @param {Array} addons Array of addon slugs.
|
||||
* @param {string} prompt Modal content.
|
||||
* @param {Function} callback The function to set the template.
|
||||
* @param {string} installedSlugs Installed slug.
|
||||
*/
|
||||
userCanInstallAddonsModal( formName, template, addons, prompt, callback, installedSlugs = '' ) {
|
||||
const spinner = '<i class="wpforms-loading-spinner wpforms-loading-white wpforms-loading-inline"></i>';
|
||||
|
||||
let confirm;
|
||||
|
||||
switch ( app.action( addons, installedSlugs ) ) {
|
||||
case 'multiple':
|
||||
case 'install':
|
||||
confirm = wpforms_form_templates.install_confirm;
|
||||
break;
|
||||
case 'activate':
|
||||
confirm = wpforms_form_templates.activate_confirm;
|
||||
break;
|
||||
default:
|
||||
confirm = wpforms_form_templates.install_confirm;
|
||||
break;
|
||||
}
|
||||
|
||||
$.confirm( {
|
||||
title: wpforms_form_templates.heads_up,
|
||||
content: prompt,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: confirm,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action() {
|
||||
this.$$confirm
|
||||
.prop( 'disabled', true )
|
||||
.html( spinner + wpforms_form_templates.activating );
|
||||
|
||||
this.$$cancel
|
||||
.prop( 'disabled', true );
|
||||
|
||||
app.installActivateAddons( addons, this, formName, template, callback );
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_form_templates.cancel,
|
||||
action() {
|
||||
WPFormsFormTemplates.selectTemplateCancel();
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the action for the addons.
|
||||
*
|
||||
* @since 1.9.0
|
||||
*
|
||||
* @param {Array} addons Addons slugs.
|
||||
* @param {string} installed Installed addon slug.
|
||||
*
|
||||
* @return {string} Action.
|
||||
*/
|
||||
action( addons, installed = '' ) {
|
||||
if ( addons.length > 1 ) {
|
||||
return 'multiple';
|
||||
}
|
||||
|
||||
if ( installed.split( ',' ).indexOf( addons[ 0 ] ) > -1 ) {
|
||||
return 'activate';
|
||||
}
|
||||
|
||||
return 'install';
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the template addon alert for non-admins.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param {string} prompt Modal content.
|
||||
*/
|
||||
userCannotInstallAddonsModal( prompt ) {
|
||||
$.alert( {
|
||||
title: wpforms_form_templates.heads_up,
|
||||
content: prompt,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
ok: {
|
||||
text: wpforms_form_templates.ok,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action() {
|
||||
WPFormsFormTemplates.selectTemplateCancel();
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Install & Activate addons via AJAX.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param {Array} addons Addons slugs.
|
||||
* @param {Object} previousModal Previous modal instance.
|
||||
* @param {string} formName Name of the form.
|
||||
* @param {string} template Template slug.
|
||||
* @param {Function} callback The function to set the template.
|
||||
*/
|
||||
installActivateAddons( addons, previousModal, formName, template, callback ) {
|
||||
const ajaxResults = [];
|
||||
const ajaxErrors = [];
|
||||
let promiseChain = false;
|
||||
|
||||
// Put each of the ajax call promises to the chain.
|
||||
addons.forEach( function( addon ) {
|
||||
if ( typeof promiseChain.done !== 'function' ) {
|
||||
promiseChain = app.installActivateAddonAjax( addon );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
promiseChain = promiseChain
|
||||
.done( function( value ) {
|
||||
ajaxResults.push( value );
|
||||
|
||||
return app.installActivateAddonAjax( addon );
|
||||
} )
|
||||
.fail( function( error ) {
|
||||
ajaxErrors.push( error );
|
||||
} );
|
||||
} );
|
||||
|
||||
promiseChain
|
||||
|
||||
// Latest promise result and error.
|
||||
.done( function( value ) {
|
||||
ajaxResults.push( value );
|
||||
} )
|
||||
.fail( function( error ) {
|
||||
ajaxErrors.push( error );
|
||||
} )
|
||||
|
||||
// Finally, resolve all the promises.
|
||||
.always( function() {
|
||||
previousModal.close();
|
||||
|
||||
if (
|
||||
ajaxResults.length > 0 &&
|
||||
wpf.listPluck( ajaxResults, 'success' ).every( Boolean ) && // Check if every `success` is true.
|
||||
ajaxErrors.length === 0
|
||||
) {
|
||||
callback( formName, template );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
app.installActivateAddonsError( formName, template, callback );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Install & Activate addons error modal.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param {string} formName Name of the form.
|
||||
* @param {string} template Template slug.
|
||||
* @param {Function} callback The function to set the template.
|
||||
*/
|
||||
installActivateAddonsError( formName, template, callback ) {
|
||||
$.confirm( {
|
||||
title: wpforms_form_templates.heads_up,
|
||||
content: wpforms_form_templates.template_addons_error,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_form_templates.use_template,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action() {
|
||||
callback( formName, template );
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_form_templates.cancel,
|
||||
action() {
|
||||
app.selectTemplateCancel();
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Install & Activate single addon via AJAX.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @param {string} addon Addon slug.
|
||||
*
|
||||
* @return {Promise} jQuery ajax call promise.
|
||||
*/
|
||||
installActivateAddonAjax( addon ) {
|
||||
const addonData = wpforms_addons[ addon ];
|
||||
const deferred = new $.Deferred();
|
||||
|
||||
if (
|
||||
! addonData ||
|
||||
[ 'activate', 'install' ].indexOf( addonData.action ) < 0
|
||||
) {
|
||||
deferred.resolve( false );
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
return $.post(
|
||||
wpforms_form_templates.ajaxurl,
|
||||
{
|
||||
action: 'wpforms_' + addonData.action + '_addon',
|
||||
nonce: wpforms_form_templates.admin_nonce,
|
||||
plugin: addonData.action === 'activate' ? addon + '/' + addon + '.php' : addonData.url,
|
||||
}
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPFormsFormTemplates.init();
|
||||
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,554 @@
|
||||
/* global wpforms_builder_help, wpf */
|
||||
|
||||
/**
|
||||
* WPForms Builder Help screen module.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var WPForms = window.WPForms || {};
|
||||
|
||||
WPForms.Admin = WPForms.Admin || {};
|
||||
WPForms.Admin.Builder = WPForms.Admin.Builder || {};
|
||||
|
||||
WPForms.Admin.Builder.Help = WPForms.Admin.Builder.Help || ( function( document, window, $ ) {
|
||||
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var el;
|
||||
|
||||
/**
|
||||
* UI functions.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var ui;
|
||||
|
||||
/**
|
||||
* Event handlers.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var event;
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var app = {
|
||||
|
||||
/**
|
||||
* Start the engine. DOM is not ready yet, use only to init something.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*/
|
||||
init: function() {
|
||||
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* DOM is fully loaded.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*/
|
||||
ready: function() {
|
||||
|
||||
app.setup();
|
||||
app.initCategories();
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup. Prepare some variables.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*/
|
||||
setup: function() {
|
||||
|
||||
// Cache DOM elements.
|
||||
el = {
|
||||
$builder: $( '#wpforms-builder' ),
|
||||
$builderForm: $( '#wpforms-builder-form' ),
|
||||
$helpBtn: $( '.js-wpforms-help' ),
|
||||
$help: $( '#wpforms-builder-help' ),
|
||||
$closeBtn: $( '#wpforms-builder-help-close' ),
|
||||
$search: $( '#wpforms-builder-help-search' ),
|
||||
$result: $( '#wpforms-builder-help-result' ),
|
||||
$noResult: $( '#wpforms-builder-help-no-result' ),
|
||||
$categories: $( '#wpforms-builder-help-categories' ),
|
||||
$footer: $( '#wpforms-builder-help-footer' ),
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*/
|
||||
events: function() {
|
||||
|
||||
// Open/close help modal.
|
||||
el.$helpBtn.on( 'click', event.openHelp );
|
||||
el.$closeBtn.on( 'click', event.closeHelp );
|
||||
|
||||
// Expand/collapse category.
|
||||
el.$categories.on( 'click', '.wpforms-builder-help-category header', event.toggleCategory );
|
||||
|
||||
// View all Category Docs button click.
|
||||
el.$categories.on( 'click', '.wpforms-builder-help-category button.viewall', event.viewAllCategoryDocs );
|
||||
|
||||
// Input into search field.
|
||||
el.$search.on( 'keyup', 'input', _.debounce( event.inputSearch, 250 ) );
|
||||
|
||||
// Clear search field.
|
||||
el.$search.on( 'click', '#wpforms-builder-help-search-clear', event.clearSearch );
|
||||
},
|
||||
|
||||
/**
|
||||
* Init (generate) categories list.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*/
|
||||
initCategories: function() {
|
||||
|
||||
// Display error if docs data is not available.
|
||||
if ( wpf.empty( wpforms_builder_help.docs ) ) {
|
||||
el.$categories.html( wp.template( 'wpforms-builder-help-categories-error' ) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var tmpl = wp.template( 'wpforms-builder-help-categories' ),
|
||||
data = {
|
||||
categories: wpforms_builder_help.categories,
|
||||
docs: app.getDocsByCategories(),
|
||||
};
|
||||
|
||||
el.$categories.html( tmpl( data ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* Init categories list.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @returns {object} Docs arranged by category.
|
||||
*/
|
||||
getDocsByCategories: function() {
|
||||
|
||||
var categories = wpforms_builder_help.categories,
|
||||
docs = wpforms_builder_help.docs || [],
|
||||
docsByCategories = {};
|
||||
|
||||
_.each( categories, function( categoryTitle, categorySlug ) {
|
||||
var docsByCategory = [];
|
||||
_.each( docs, function( doc ) {
|
||||
if ( doc.categories && doc.categories.indexOf( categorySlug ) > -1 ) {
|
||||
docsByCategory.push( doc );
|
||||
}
|
||||
} );
|
||||
docsByCategories[ categorySlug ] = docsByCategory;
|
||||
} );
|
||||
|
||||
return docsByCategories;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get docs recommended by search term.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @param {string} term Search term.
|
||||
*
|
||||
* @returns {Array} Recommended docs.
|
||||
*/
|
||||
getRecommendedDocs: function( term ) {
|
||||
|
||||
if ( wpf.empty( term ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
term = term.toLowerCase();
|
||||
|
||||
var docs = wpforms_builder_help.docs,
|
||||
recommendedDocs = [];
|
||||
|
||||
if ( wpf.empty( wpforms_builder_help.context.docs[ term ] ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
_.each( wpforms_builder_help.context.docs[ term ], function( docId ) {
|
||||
if ( ! wpf.empty( docs[ docId ] ) ) {
|
||||
recommendedDocs.push( docs[ docId ] );
|
||||
}
|
||||
} );
|
||||
|
||||
return recommendedDocs;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get docs filtered by search term.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @param {string} term Search term.
|
||||
*
|
||||
* @returns {Array} Filtered docs.
|
||||
*/
|
||||
getFilteredDocs: function( term ) {
|
||||
|
||||
if ( wpf.empty( term ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
var docs = wpforms_builder_help.docs,
|
||||
filteredDocs = [];
|
||||
|
||||
term = term.toLowerCase();
|
||||
|
||||
_.each( docs, function( doc ) {
|
||||
if ( doc.title && doc.title.toLowerCase().indexOf( term ) > -1 ) {
|
||||
filteredDocs.push( doc );
|
||||
}
|
||||
} );
|
||||
|
||||
return filteredDocs;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the current context (state) of the form builder.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @returns {string} Builder context string. For example 'fields/add_field' or 'settings/notifications'.
|
||||
*/
|
||||
getBuilderContext: function() {
|
||||
|
||||
// New (not saved) form.
|
||||
if ( wpf.empty( el.$builderForm.data( 'id' ) ) ) {
|
||||
return 'new_form';
|
||||
}
|
||||
|
||||
// Determine builder panel and section.
|
||||
var panel = el.$builder.find( '#wpforms-panels-toggle button.active' ).data( 'panel' ),
|
||||
$panel = el.$builder.find( '#wpforms-panel-' + panel ),
|
||||
section = '',
|
||||
subsection = '',
|
||||
context;
|
||||
|
||||
switch ( panel ) {
|
||||
case 'fields':
|
||||
section = $panel.find( '.wpforms-panel-sidebar .wpforms-tab a.active' ).parent().attr( 'id' );
|
||||
break;
|
||||
case 'setup':
|
||||
section = '';
|
||||
break;
|
||||
default:
|
||||
section = $panel.find( '.wpforms-panel-sidebar a.active' ).data( 'section' );
|
||||
}
|
||||
|
||||
section = ! wpf.empty( section ) ? section.replace( /-/g, '_' ) : '';
|
||||
|
||||
// Detect field type.
|
||||
if ( section === 'field_options' ) {
|
||||
subsection = $panel.find( '#wpforms-field-options .wpforms-field-option:visible .wpforms-field-option-hidden-type' ).val();
|
||||
}
|
||||
|
||||
// Combine to context array.
|
||||
context = [ panel, section, subsection ].filter( function( el ) {
|
||||
return ! wpf.empty( el ) && el !== 'default';
|
||||
} );
|
||||
|
||||
// Return imploded string.
|
||||
return context.join( '/' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the search term for the current builder context.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @returns {string} Builder context term string.
|
||||
*/
|
||||
getBuilderContextTerm: function() {
|
||||
|
||||
return wpforms_builder_help.context.terms[ app.getBuilderContext() ] || '';
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* UI functions.
|
||||
*/
|
||||
ui = {
|
||||
|
||||
/**
|
||||
* Configuration.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
config: {
|
||||
speed: 300, // Fading/sliding duration in milliseconds.
|
||||
},
|
||||
|
||||
/**
|
||||
* Display the element by fading them to opaque using CSS.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @param {jQuery} $el Element object.
|
||||
*/
|
||||
fadeIn: function( $el ) {
|
||||
|
||||
if ( ! $el.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$el.css( {
|
||||
display: '',
|
||||
transition: `opacity ${ui.config.speed}ms ease-in 0s`,
|
||||
} );
|
||||
|
||||
setTimeout( function() {
|
||||
$el.css( 'opacity', '1' );
|
||||
}, 0 );
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide the element by fading them to transparent using CSS.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @param {jQuery} $el Element object.
|
||||
*/
|
||||
fadeOut: function( $el ) {
|
||||
|
||||
if ( ! $el.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$el.css( {
|
||||
opacity: '0',
|
||||
transition: `opacity ${ui.config.speed}ms ease-in 0s`,
|
||||
} );
|
||||
|
||||
setTimeout( function() {
|
||||
$el.css( 'display', 'none' );
|
||||
}, ui.config.speed );
|
||||
},
|
||||
|
||||
/**
|
||||
* Collapse all categories.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*/
|
||||
collapseAllCategories: function() {
|
||||
|
||||
el.$categories.find( '.wpforms-builder-help-category' ).removeClass( 'opened' );
|
||||
el.$categories.find( '.wpforms-builder-help-docs' ).slideUp();
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handlers.
|
||||
*/
|
||||
event = {
|
||||
|
||||
/**
|
||||
* Open help modal.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @param {object} e Event object.
|
||||
*/
|
||||
openHelp: function( e ) {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
$( 'body' ).addClass( 'wpforms-builder-help-open' );
|
||||
|
||||
var $firstCategory = el.$categories.find( '.wpforms-builder-help-category' ).first(),
|
||||
builderContextTerm = app.getBuilderContextTerm();
|
||||
|
||||
if ( builderContextTerm === '' && ! $firstCategory.hasClass( 'opened' ) ) {
|
||||
$firstCategory.find( 'header' ).first().trigger( 'click' );
|
||||
} else {
|
||||
ui.collapseAllCategories();
|
||||
}
|
||||
|
||||
el.$search.find( 'input' ).val( builderContextTerm ).trigger( 'keyup' );
|
||||
|
||||
ui.fadeIn( el.$help );
|
||||
|
||||
setTimeout( function() {
|
||||
|
||||
ui.fadeIn( el.$result );
|
||||
ui.fadeIn( el.$categories );
|
||||
ui.fadeIn( el.$footer );
|
||||
|
||||
}, ui.config.speed );
|
||||
},
|
||||
|
||||
/**
|
||||
* Close help modal.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @param {object} e Event object.
|
||||
*/
|
||||
closeHelp: function( e ) {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
$( 'body' ).removeClass( 'wpforms-builder-help-open' );
|
||||
|
||||
ui.fadeOut( el.$result );
|
||||
ui.fadeOut( el.$categories );
|
||||
ui.fadeOut( el.$footer );
|
||||
|
||||
ui.fadeOut( el.$help );
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle category.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @param {object} e Event object.
|
||||
*/
|
||||
toggleCategory: function( e ) {
|
||||
|
||||
var $category = $( this ).parent(),
|
||||
$categoryDocs = $category.find( '.wpforms-builder-help-docs' );
|
||||
|
||||
if ( ! $categoryDocs.is( ':visible' ) ) {
|
||||
$category.addClass( 'opened' );
|
||||
} else {
|
||||
$category.removeClass( 'opened' );
|
||||
}
|
||||
|
||||
$categoryDocs.stop().slideToggle( ui.config.speed );
|
||||
},
|
||||
|
||||
/**
|
||||
* View All Category Docs button click.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @param {object} e Event object.
|
||||
*/
|
||||
viewAllCategoryDocs: function( e ) {
|
||||
|
||||
var $btn = $( this );
|
||||
|
||||
$btn.prev( 'div' ).stop().slideToggle( ui.config.speed, function() {
|
||||
$btn.closest( '.wpforms-builder-help-category' ).addClass( 'viewall' );
|
||||
} );
|
||||
ui.fadeOut( $btn );
|
||||
$btn.slideUp();
|
||||
},
|
||||
|
||||
/**
|
||||
* Input into search field.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @param {object} e Event object.
|
||||
*/
|
||||
inputSearch: function( e ) {
|
||||
|
||||
var $input = $( this ),
|
||||
term = $input.val();
|
||||
|
||||
var tmpl = wp.template( 'wpforms-builder-help-docs' ),
|
||||
recommendedDocs = app.getRecommendedDocs( term ),
|
||||
filteredDocs = event.removeDuplicates( recommendedDocs, app.getFilteredDocs( term ) ),
|
||||
resultHTML = '';
|
||||
|
||||
el.$search.toggleClass( 'wpforms-empty', ! term );
|
||||
|
||||
if ( ! wpf.empty( recommendedDocs ) ) {
|
||||
resultHTML += tmpl( {
|
||||
docs: recommendedDocs,
|
||||
} );
|
||||
}
|
||||
|
||||
if ( ! wpf.empty( filteredDocs ) ) {
|
||||
resultHTML += tmpl( {
|
||||
docs: filteredDocs,
|
||||
} );
|
||||
}
|
||||
|
||||
el.$noResult.toggle( resultHTML === '' && term !== '' );
|
||||
|
||||
el.$result.html( resultHTML );
|
||||
|
||||
el.$help[0].scrollTop = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove duplicated items in the filtered docs.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @param {Array} recommendedDocs Recommended docs.
|
||||
* @param {Array} filteredDocs Filtered docs.
|
||||
*
|
||||
* @returns {Array} Filtered docs without duplicated items in the recommended docs.
|
||||
*/
|
||||
removeDuplicates: function( recommendedDocs, filteredDocs ) {
|
||||
|
||||
if ( wpf.empty( recommendedDocs ) || wpf.empty( filteredDocs ) ) {
|
||||
return filteredDocs;
|
||||
}
|
||||
|
||||
var docs = [];
|
||||
|
||||
for ( var i = 0; i < recommendedDocs.length, i++; ) {
|
||||
for ( var k = 0; k < filteredDocs.length, k++; ) {
|
||||
if ( filteredDocs[ k ].url !== recommendedDocs[ i ].url ) {
|
||||
docs.push( filteredDocs[ k ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return docs;
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear search field.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @param {object} e Event object.
|
||||
*/
|
||||
clearSearch: function( e ) {
|
||||
|
||||
el.$search.find( 'input' ).val( '' ).trigger( 'keyup' );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPForms.Admin.Builder.Help.init();
|
||||
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,185 @@
|
||||
/* global WPFormsUtils, wpf, wpforms_builder */
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
/**
|
||||
* WPForms Image Upload Control for Builder Settings.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*/
|
||||
|
||||
var WPForms = window.WPForms || {}; // eslint-disable-line no-var
|
||||
WPForms.Admin = WPForms.Admin || {};
|
||||
WPForms.Admin.Builder = WPForms.Admin.Builder || {};
|
||||
WPForms.Admin.Builder.Settings = WPForms.Admin.Builder.Settings || {};
|
||||
|
||||
/**
|
||||
* Image Upload functionality for Settings.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*/
|
||||
WPForms.Admin.Builder.Settings.ImageUpload = WPForms.Admin.Builder.Settings.ImageUpload || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Image Upload Control methods and properties.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*/
|
||||
init() {
|
||||
$( document ).ready( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*/
|
||||
ready() {
|
||||
app.$builder = $( '#wpforms-builder' );
|
||||
|
||||
app.bindEvents();
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*/
|
||||
bindEvents() {
|
||||
$( document ).on( 'click', '.wpforms-image-upload-button', app.openMediaUploader );
|
||||
$( document ).on( 'click', '.wpforms-image-remove-button', app.removeImage );
|
||||
},
|
||||
|
||||
/**
|
||||
* Open media uploader when upload button is clicked.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
*/
|
||||
openMediaUploader( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
const $control = $( this ).closest( '.wpforms-image-upload-control' );
|
||||
const controlId = $control.attr( 'id' );
|
||||
|
||||
app.frames = app.frames ?? {};
|
||||
|
||||
// If the media frame already exists, reopen it.
|
||||
if ( app.frames[ controlId ] ) {
|
||||
app.frame = app.frames[ controlId ];
|
||||
app.frame.open();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a new media frame.
|
||||
app.frame = wpf.initMediaLibrary( {
|
||||
extensions: wpforms_builder.upload_image_extensions,
|
||||
extensionsError: wpforms_builder.upload_image_extensions_error,
|
||||
buttonText: wpforms_builder.upload_image_button,
|
||||
} );
|
||||
|
||||
// When an image is selected in the media frame.
|
||||
app.frame.on( 'select', function() {
|
||||
// Get media attachment details.
|
||||
const attachment = app.frame.state().get( 'selection' ).first().toJSON();
|
||||
|
||||
// Set image to the control.
|
||||
app.setImage( $control, attachment );
|
||||
} );
|
||||
|
||||
// Finally, open the modal.
|
||||
app.frame.open();
|
||||
|
||||
// Store the frame.
|
||||
app.frames[ controlId ] = app.frame;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get control elements.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*
|
||||
* @param {Object} $control Control element.
|
||||
*
|
||||
* @return {Object} Control elements.
|
||||
*/
|
||||
getControlElements( $control ) {
|
||||
return {
|
||||
$control,
|
||||
$idField: $control.find( '.wpforms-image-upload-id' ),
|
||||
$urlField: $control.find( '.wpforms-image-upload-url' ),
|
||||
$preview: $control.find( '.wpforms-image-preview img' ),
|
||||
$uploadBtn: $control.find( '.wpforms-image-upload-button' ),
|
||||
$removeBtn: $control.find( '.wpforms-image-remove-button' ),
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Set image to the control.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*
|
||||
* @param {jQuery} $control Control element.
|
||||
* @param {Object} attachment Attachment data.
|
||||
*/
|
||||
setImage( $control, attachment ) {
|
||||
// Get control elements.
|
||||
const { $idField, $urlField, $preview, $uploadBtn, $removeBtn } = app.getControlElements( $control );
|
||||
|
||||
// Update preview.
|
||||
$preview.attr( 'src', attachment.url );
|
||||
|
||||
// Update fields.
|
||||
$idField.val( attachment.id );
|
||||
$urlField.val( attachment.url );
|
||||
|
||||
// Toggle buttons
|
||||
$uploadBtn.addClass( 'wpforms-hidden' );
|
||||
$removeBtn.removeClass( 'wpforms-hidden' );
|
||||
|
||||
// Trigger custom change event.
|
||||
WPFormsUtils.triggerEvent( app.$builder, 'wpformsImageUploadChange', [ $control, attachment ] );
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove image when remove button is clicked.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
*/
|
||||
removeImage( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
const $control = $( this ).closest( '.wpforms-image-upload-control' );
|
||||
const { $idField, $urlField, $preview, $uploadBtn, $removeBtn } = app.getControlElements( $control );
|
||||
|
||||
// Reset preview.
|
||||
$preview.attr( 'src', '' );
|
||||
|
||||
// Clear fields.
|
||||
$idField.val( '' );
|
||||
$urlField.val( '' );
|
||||
|
||||
// Toggle buttons.
|
||||
$uploadBtn.removeClass( 'wpforms-hidden' );
|
||||
$removeBtn.addClass( 'wpforms-hidden' );
|
||||
|
||||
// Trigger custom change event.
|
||||
WPFormsUtils.triggerEvent( app.$builder, 'wpformsImageUploadChange', [ $control, null ] );
|
||||
},
|
||||
};
|
||||
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPForms.Admin.Builder.Settings.ImageUpload.init();
|
||||
+1
@@ -0,0 +1 @@
|
||||
var WPForms=window.WPForms||{};WPForms.Admin=WPForms.Admin||{},WPForms.Admin.Builder=WPForms.Admin.Builder||{},WPForms.Admin.Builder.Settings=WPForms.Admin.Builder.Settings||{},WPForms.Admin.Builder.Settings.ImageUpload=WPForms.Admin.Builder.Settings.ImageUpload||((e,d)=>{let a={init(){d(e).ready(a.ready)},ready(){a.$builder=d("#wpforms-builder"),a.bindEvents()},bindEvents(){d(e).on("click",".wpforms-image-upload-button",a.openMediaUploader),d(e).on("click",".wpforms-image-remove-button",a.removeImage)},openMediaUploader(e){e.preventDefault();let r=d(this).closest(".wpforms-image-upload-control");e=r.attr("id");a.frames=a.frames??{},a.frames[e]?(a.frame=a.frames[e],a.frame.open()):(a.frame=wpf.initMediaLibrary({extensions:wpforms_builder.upload_image_extensions,extensionsError:wpforms_builder.upload_image_extensions_error,buttonText:wpforms_builder.upload_image_button}),a.frame.on("select",function(){var e=a.frame.state().get("selection").first().toJSON();a.setImage(r,e)}),a.frame.open(),a.frames[e]=a.frame)},getControlElements(e){return{$control:e,$idField:e.find(".wpforms-image-upload-id"),$urlField:e.find(".wpforms-image-upload-url"),$preview:e.find(".wpforms-image-preview img"),$uploadBtn:e.find(".wpforms-image-upload-button"),$removeBtn:e.find(".wpforms-image-remove-button")}},setImage(e,r){var{$idField:o,$urlField:i,$preview:m,$uploadBtn:t,$removeBtn:d}=a.getControlElements(e);m.attr("src",r.url),o.val(r.id),i.val(r.url),t.addClass("wpforms-hidden"),d.removeClass("wpforms-hidden"),WPFormsUtils.triggerEvent(a.$builder,"wpformsImageUploadChange",[e,r])},removeImage(e){e.preventDefault();var e=d(this).closest(".wpforms-image-upload-control"),{$idField:r,$urlField:o,$preview:i,$uploadBtn:m,$removeBtn:t}=a.getControlElements(e);i.attr("src",""),r.val(""),o.val(""),m.removeClass("wpforms-hidden"),t.addClass("wpforms-hidden"),WPFormsUtils.triggerEvent(a.$builder,"wpformsImageUploadChange",[e,null])}};return a})(document,(window,jQuery)),WPForms.Admin.Builder.Settings.ImageUpload.init();
|
||||
+443
@@ -0,0 +1,443 @@
|
||||
/* global wpforms_builder, WPFormsBuilder */
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
var WPForms = window.WPForms || {}; // eslint-disable-line no-var
|
||||
WPForms.Admin = WPForms.Admin || {};
|
||||
WPForms.Admin.Builder = WPForms.Admin.Builder || {};
|
||||
|
||||
/**
|
||||
* Multiple Choices functionality.
|
||||
*
|
||||
* @since 1.9.8.3
|
||||
*/
|
||||
WPForms.Admin.Builder.MultipleChoices = WPForms.Admin.Builder.MultipleChoices || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Multiple Choices methods and properties.
|
||||
*
|
||||
* @since 1.9.8.3
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.9.8.3
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Init.
|
||||
*
|
||||
* @since 1.9.8.3
|
||||
*/
|
||||
ready() {
|
||||
app.bindEvents();
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind actions.
|
||||
*
|
||||
* @since 1.9.8.3
|
||||
*/
|
||||
// eslint-disable-next-line max-lines-per-function
|
||||
bindEvents() {
|
||||
// Cache builder element.
|
||||
app.$builder = $( '#wpforms-builder' );
|
||||
|
||||
// Switch Add other option toggle.
|
||||
app.$builder.on( 'change', '.wpforms-field-option-row-choices_other input', app.toggleOtherOption );
|
||||
|
||||
// Real-time update Other input placeholder in preview.
|
||||
app.$builder.on( 'input', '.wpforms-field-option-row-other_placeholder input', app.updateOtherOptionPlaceholder );
|
||||
|
||||
// Real-time update Other input size in preview.
|
||||
app.$builder.on( 'change', '.wpforms-field-option-row-other_size select', app.updateOptionInputFieldSize );
|
||||
|
||||
// When AI inserts choices, append the Other choice if the toggle is enabled.
|
||||
$( document ).on( 'wpformsAIModalAfterChoicesInsert', app.appendOtherOption );
|
||||
|
||||
// Real-time preview Other input value while typing in the Other choice Value when Show Values is enabled.
|
||||
app.$builder.on( 'input', '.wpforms-field-option-row-choices li.wpforms-choice-other-option input.value', app.updateOptionInputPreview );
|
||||
|
||||
// When Dynamic Choices is toggled ON, force-disable Other option.
|
||||
app.$builder.on( 'change', '.wpforms-field-option-row-dynamic_choices select', app.toggleDynamicChoices );
|
||||
|
||||
app.$builder.on( 'wpformsChoicesSetDefault', app.updateDefaultOptionState );
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the preview of the "Other" input field in a form field based on the updated option value.
|
||||
* This method checks if the "Show Values" option is enabled, fetches the current value from the input field,
|
||||
* and updates the corresponding preview input with the value or a placeholder.
|
||||
*
|
||||
* @since 1.9.8.3
|
||||
*/
|
||||
updateOptionInputPreview() {
|
||||
const $val = $( this );
|
||||
const $list = $val.closest( '.choices-list' );
|
||||
const fieldID = $list.data( 'field-id' );
|
||||
const $options = $( '#wpforms-field-option-' + fieldID );
|
||||
const showValuesOn = $options.find( '.wpforms-field-option-row-show_values input' ).is( ':checked' );
|
||||
|
||||
if ( ! showValuesOn ) {
|
||||
return;
|
||||
}
|
||||
const value = $val.val();
|
||||
const $preview = $( '#wpforms-field-' + fieldID );
|
||||
const $otherInput = $preview.find( '.wpforms-other-input' );
|
||||
const placeholder = $options.find( '.wpforms-field-option-row-other_placeholder input' ).val() || '';
|
||||
$otherInput.val( value ?? placeholder );
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the size of an option input field based on its selected value.
|
||||
*
|
||||
* This method retrieves the selected value of a dropdown associated with an option input field,
|
||||
* determines its size, and applies the updated size to the respective container using the application logic.
|
||||
*
|
||||
* @since 1.9.8.3
|
||||
*/
|
||||
updateOptionInputFieldSize() {
|
||||
const $select = $( this );
|
||||
const fieldID = $select.closest( '.wpforms-field-option-row' ).data( 'field-id' );
|
||||
const val = $select.val() || 'medium';
|
||||
app.setOtherSizeOnContainer( fieldID, val );
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the default option state for a choice field, particularly handling behavior for Radio fields
|
||||
* and the "Other" choice option. Manages UI adjustments, such as showing or hiding the "Other" input field
|
||||
* in the preview based on the selected default option.
|
||||
*
|
||||
* @since 1.9.8.3
|
||||
*
|
||||
* @param {Event} e The event object triggered during the state change.
|
||||
* @param {HTMLElement} el The HTML element representing the choice being toggled.
|
||||
*/
|
||||
updateDefaultOptionState( e, el ) {
|
||||
const $this = $( el ),
|
||||
$choicesList = $this.closest( '.choices-list' ),
|
||||
fieldType = $choicesList.data( 'field-type' );
|
||||
|
||||
if ( fieldType !== 'radio' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fieldId = $choicesList.data( 'field-id' );
|
||||
|
||||
// If toggling default for Radio field's Other choice, show/hide preview Other input accordingly.
|
||||
const $li = $this.closest( 'li' ),
|
||||
$previewField = $( '#wpforms-field-' + fieldId ),
|
||||
$otherInput = $previewField.find( '.wpforms-other-input' );
|
||||
|
||||
if ( ! $li.hasClass( 'wpforms-choice-other-option' ) ) {
|
||||
$otherInput.addClass( 'wpforms-hidden' ).val( '' );
|
||||
return;
|
||||
}
|
||||
|
||||
// Toggle visibility based on whether this radio is checked.
|
||||
const checked = $this.is( ':checked' );
|
||||
$otherInput.toggleClass( 'wpforms-hidden', ! checked );
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles the "Other" option functionality in the options interface of a form field.
|
||||
* This includes adding or removing the "Other" choice, updating its placeholder and size options,
|
||||
* and updating the preview state accordingly.
|
||||
*
|
||||
* @since 1.9.8.3
|
||||
*
|
||||
* @param {Event} e The event object triggered during the state change.
|
||||
*/
|
||||
toggleOtherOption( e ) {
|
||||
const $this = $( this ),
|
||||
$optionRow = $this.closest( '.wpforms-field-option-row' ),
|
||||
fieldID = $optionRow.data( 'field-id' ),
|
||||
$fieldOptions = $( '#wpforms-field-option-' + fieldID ),
|
||||
checked = $this.is( ':checked' ),
|
||||
type = $fieldOptions.find( '.wpforms-field-option-hidden-type' ).val(),
|
||||
$choicesList = $( '#wpforms-field-option-row-' + fieldID + '-choices .choices-list' );
|
||||
|
||||
let id = $choicesList.attr( 'data-next-id' );
|
||||
|
||||
if ( checked ) {
|
||||
app.fieldChoiceAddOther( e, $( this ), id );
|
||||
id++;
|
||||
$choicesList.attr( 'data-next-id', id );
|
||||
} else {
|
||||
$choicesList.find( 'li.wpforms-choice-other-option' ).remove();
|
||||
$( '#wpforms-field-' + fieldID ).find( '.wpforms-other-input' ).addClass( 'wpforms-hidden' );
|
||||
}
|
||||
|
||||
// Toggle the visibility of the Other Placeholder and Field Size option rows.
|
||||
$fieldOptions.find( '.wpforms-field-option-row-other_placeholder' ).toggleClass( 'wpforms-hidden', ! checked );
|
||||
$fieldOptions.find( '.wpforms-field-option-row-other_size' ).toggleClass( 'wpforms-hidden', ! checked );
|
||||
|
||||
// Apply/remove container size class accordingly.
|
||||
if ( checked ) {
|
||||
const sizeVal = $fieldOptions.find( '.wpforms-field-option-row-other_size select' ).val() || 'medium';
|
||||
app.setOtherSizeOnContainer( fieldID, sizeVal );
|
||||
} else {
|
||||
app.setOtherSizeOnContainer( fieldID, null );
|
||||
}
|
||||
|
||||
// Update preview.
|
||||
WPFormsBuilder.fieldChoiceUpdate( type, fieldID );
|
||||
app.updatePreviewState( fieldID );
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles the placeholder attribute of the "other" input field in a form preview
|
||||
* based on the value from the corresponding field option settings.
|
||||
*
|
||||
* Finds the relevant field ID based on the context of the input element, and
|
||||
* updates the placeholder text of the "other" input field in the preview if it exists.
|
||||
*
|
||||
* @return {void} Does not return a value.
|
||||
*/
|
||||
updateOtherOptionPlaceholder() {
|
||||
const $input = $( this );
|
||||
const fieldID = $input.closest( '.wpforms-field-option-row' ).data( 'field-id' );
|
||||
const value = $input.val();
|
||||
const $previewOther = $( '#wpforms-field-' + fieldID + ' .wpforms-other-input' );
|
||||
if ( $previewOther.length ) {
|
||||
$previewOther.attr( 'placeholder', value );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles the state of dynamic choices for a select input field.
|
||||
* Verifies if a selected value exists, performs operations on associated field options,
|
||||
* and updates the preview state based on user interaction.
|
||||
*
|
||||
* @since 1.9.8.3
|
||||
*
|
||||
* @return {void} Does not return a value.
|
||||
*/
|
||||
toggleDynamicChoices() {
|
||||
const $select = $( this );
|
||||
const dynamicOn = $select.val() !== '';
|
||||
if ( ! dynamicOn ) {
|
||||
return;
|
||||
}
|
||||
const fieldID = $select.closest( '.wpforms-field-option-row' ).data( 'field-id' );
|
||||
const $fieldOptions = $( '#wpforms-field-option-' + fieldID );
|
||||
const $otherToggle = $fieldOptions.find( '.wpforms-field-option-row-choices_other input' );
|
||||
|
||||
if ( $otherToggle.is( ':checked' ) ) {
|
||||
$otherToggle.prop( 'checked', false ).trigger( 'change' );
|
||||
}
|
||||
|
||||
app.updatePreviewState( fieldID );
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new "Other" choice element.
|
||||
*
|
||||
* @since 1.9.8.3
|
||||
*
|
||||
* @param {jQuery} $choicesList The choices list container.
|
||||
* @param {string} fieldID Field ID.
|
||||
* @param {number} key Next choice key.
|
||||
*
|
||||
* @return {jQuery} The cloned and prepared Other choice element.
|
||||
*/
|
||||
createOtherChoice( $choicesList, fieldID, key ) {
|
||||
const $last = $choicesList.children( 'li' ).last();
|
||||
const $clone = $last.clone();
|
||||
|
||||
const otherLabel = wpforms_builder.other;
|
||||
|
||||
$clone.attr( 'data-key', key );
|
||||
$clone.find( 'input.label' ).val( otherLabel ).attr( 'name', `fields[${ fieldID }][choices][${ key }][label]` );
|
||||
$clone.find( 'input.value' ).val( '' ).attr( 'name', `fields[${ fieldID }][choices][${ key }][value]` );
|
||||
$clone.find( '.wpforms-image-upload input.source' ).val( '' ).attr( 'name', `fields[${ fieldID }][choices][${ key }][image]` );
|
||||
$clone.find( '.wpforms-icon-select input.source-icon' ).val( wpforms_builder.icon_choices.default_icon ).attr( 'name', `fields[${ fieldID }][choices][${ key }][icon]` );
|
||||
$clone.find( '.wpforms-icon-select input.source-icon-style' ).val( wpforms_builder.icon_choices.default_icon_style ).attr( 'name', `fields[${ fieldID }][choices][${ key }][icon_style]` );
|
||||
$clone.find( '.wpforms-icon-select .ic-fa-preview' ).removeClass().addClass( `ic-fa-preview ic-fa-${ wpforms_builder.icon_choices.default_icon_style } ic-fa-${ wpforms_builder.icon_choices.default_icon }` );
|
||||
$clone.find( '.wpforms-icon-select .ic-fa-preview + span' ).text( wpforms_builder.icon_choices.default_icon );
|
||||
$clone.find( 'input.default' ).attr( 'name', `fields[${ fieldID }][choices][${ key }][default]` ).prop( 'checked', false );
|
||||
$clone.find( '.preview' ).empty();
|
||||
$clone.find( '.wpforms-image-upload-add' ).show();
|
||||
|
||||
// Mark as special "Other" item for clarity and sorting prevention.
|
||||
$clone.addClass( 'wpforms-choice-other-option not-draggable' );
|
||||
$clone.find( '.move, .add, .remove' ).addClass( 'wpforms-disabled' );
|
||||
|
||||
// Add hidden input flag to identify this choice as "Other".
|
||||
$clone.find( 'input.other-flag' ).remove();
|
||||
$clone.append(
|
||||
`<input type="hidden" class="other-flag" name="fields[${ fieldID }][choices][${ key }][other]" value="1">`
|
||||
);
|
||||
|
||||
return $clone;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add Other choice to a field.
|
||||
*
|
||||
* @since 1.9.8.3
|
||||
*
|
||||
* @param {Event|null} event Event object.
|
||||
* @param {Element} el The toggle element.
|
||||
* @param {number} key Next choice key.
|
||||
*/
|
||||
fieldChoiceAddOther( event, el, key ) {
|
||||
const $optionRow = $( el ).closest( '.wpforms-field-option-row' );
|
||||
const fieldID = $optionRow.data( 'field-id' );
|
||||
const $choicesList = $( `#wpforms-field-option-row-${ fieldID }-choices .choices-list` );
|
||||
|
||||
const $clone = app.createOtherChoice( $choicesList, fieldID, key );
|
||||
$choicesList.append( $clone );
|
||||
},
|
||||
|
||||
/**
|
||||
* Append Other option at the end of the choices list when toggle is on.
|
||||
*
|
||||
* @since 1.9.8.3
|
||||
*
|
||||
* @param {Object} event Event object.
|
||||
*/
|
||||
appendOtherOption( event ) {
|
||||
const fieldId = event?.detail?.fieldId;
|
||||
const $fieldOptions = $( `#wpforms-field-option-${ fieldId }` );
|
||||
const $toggle = $fieldOptions.find( '.wpforms-field-option-row-choices_other input' );
|
||||
|
||||
if ( ! $toggle.length || ! $toggle.is( ':checked' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $choicesList = $( `#wpforms-field-option-row-${ fieldId }-choices .choices-list` );
|
||||
|
||||
// Prevent duplicate Other choice.
|
||||
if ( $choicesList.find( 'li.wpforms-choice-other-option' ).length > 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
let nextId = parseInt( $choicesList.attr( 'data-next-id' ), 10 );
|
||||
nextId = isNaN( nextId ) ? 1 : nextId;
|
||||
|
||||
const $clone = app.createOtherChoice( $choicesList, fieldId, nextId );
|
||||
$choicesList.append( $clone );
|
||||
$choicesList.attr( 'data-next-id', nextId + 1 );
|
||||
|
||||
const type = $fieldOptions.find( '.wpforms-field-option-hidden-type' ).val();
|
||||
WPFormsBuilder.fieldChoiceUpdate( type, fieldId );
|
||||
},
|
||||
|
||||
/**
|
||||
* Set size for the container of other option to reach the correct style changes.
|
||||
*
|
||||
* @since 1.9.8.3
|
||||
*
|
||||
* @param {string} fieldId Field ID.
|
||||
* @param {string} size The size.
|
||||
*/
|
||||
setOtherSizeOnContainer( fieldId, size ) {
|
||||
const $container = $( '#wpforms-field-' + fieldId + '.wpforms-field-radio' );
|
||||
|
||||
$container.removeClass( 'size-small size-medium size-large' );
|
||||
|
||||
if ( size ) {
|
||||
$container.addClass( 'size-' + size );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Show other input on the preview.
|
||||
*
|
||||
* @since 1.9.8.3
|
||||
*
|
||||
* @param {jQuery} $field A field or list of fields.
|
||||
*/
|
||||
showPreviewOther( $field ) {
|
||||
const $otherInput = $field.find( '.wpforms-other-input' );
|
||||
|
||||
if ( ! $otherInput.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$otherInput.removeClass( 'wpforms-hidden' );
|
||||
|
||||
const $otherRadio = $field.find( 'li.wpforms-other-choice input[type="radio"]' );
|
||||
|
||||
if ( ! $otherRadio.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$otherRadio.val( $otherInput.val() );
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide other input on the preview.
|
||||
*
|
||||
* @since 1.9.8.3
|
||||
*
|
||||
* @param {jQuery} $field A field or list of fields.
|
||||
*/
|
||||
hidePreviewOther( $field ) {
|
||||
const $otherInput = $field.find( '.wpforms-other-input' );
|
||||
|
||||
if ( ! $otherInput.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$otherInput.addClass( 'wpforms-hidden' ).val( '' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update other input preview state configuration changes.
|
||||
*
|
||||
* @since 1.9.8.3
|
||||
*
|
||||
* @param {number|string} fieldId Field ID.
|
||||
*/
|
||||
updatePreviewState( fieldId ) {
|
||||
const $options = $( '#wpforms-field-option-' + fieldId );
|
||||
const $preview = $( '#wpforms-field-' + fieldId );
|
||||
const addOtherOn = $options.find( '.wpforms-field-option-row-choices_other input' ).is( ':checked' );
|
||||
|
||||
// 1. Handle Add Other toggle.
|
||||
if ( ! addOtherOn ) {
|
||||
app.hidePreviewOther( $preview );
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Show/hide Other input in preview depending on radio state.
|
||||
const $otherRadio = $options.find( '.choices-list li.wpforms-choice-other-option input[type="radio"]' );
|
||||
if ( $otherRadio.length && $otherRadio.is( ':checked' ) ) {
|
||||
app.showPreviewOther( $preview );
|
||||
} else {
|
||||
app.hidePreviewOther( $preview );
|
||||
}
|
||||
|
||||
// 3. Handle the Show Values toggle.
|
||||
const $otherInput = $preview.find( '.wpforms-other-input' );
|
||||
|
||||
if ( ! $otherInput.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const showValuesOn = $options.find( '.wpforms-field-option-row-show_values input' ).is( ':checked' );
|
||||
const placeholder = $options.find( '.wpforms-field-option-row-other_placeholder input' ).val() || '';
|
||||
|
||||
if ( ! showValuesOn ) {
|
||||
$otherInput.val( '' ).attr( 'placeholder', placeholder );
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. Sync value from choices into preview input.
|
||||
const val = $options.find( '.choices-list li.wpforms-choice-other-option input.value' ).val() || '';
|
||||
$otherInput.val( val ).attr( 'placeholder', placeholder );
|
||||
},
|
||||
};
|
||||
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPForms.Admin.Builder.MultipleChoices.init();
|
||||
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,236 @@
|
||||
/* global wpforms_builder, wpf */
|
||||
|
||||
/**
|
||||
* Form Builder Panel Loader module.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
|
||||
var WPForms = window.WPForms || {}; // eslint-disable-line no-var
|
||||
|
||||
WPForms.Admin = WPForms.Admin || {};
|
||||
WPForms.Admin.Builder = WPForms.Admin.Builder || {};
|
||||
|
||||
WPForms.Admin.Builder.PanelLoader = WPForms.Admin.Builder.PanelLoader || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const el = {};
|
||||
|
||||
/**
|
||||
* Runtime variables.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const vars = [];
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* DOM is fully loaded.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
ready() {
|
||||
app.setup();
|
||||
app.events();
|
||||
|
||||
el.$builder.trigger( 'wpformsBuilderLoaderReady' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup. Prepare some variables.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
setup() {
|
||||
// Cache DOM elements.
|
||||
el.$builder = $( '#wpforms-builder' );
|
||||
el.$form = $( '#wpforms-builder-form' );
|
||||
el.$panels = el.$builder.find( '.wpforms-panels' );
|
||||
|
||||
// Init vars.
|
||||
vars.currentPanel = wpf.getQueryString( 'view' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
events() {
|
||||
// Panel switching.
|
||||
el.$builder.on( 'wpformsPanelSwitch', function( e, panel ) {
|
||||
// Skip if the panel is still loading.
|
||||
if ( el.$builder.find( `.wpforms-panel-${ panel }-button .wpforms-loading-spinner` ).length ) {
|
||||
e.preventDefault();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Open the panel if it is already loaded.
|
||||
if ( el.$panels.find( '#wpforms-panel-' + panel ).length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Load panel.
|
||||
e.preventDefault();
|
||||
app.loadPanel( panel );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Load panel.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} panel Panel name.
|
||||
*/
|
||||
loadPanel( panel ) {
|
||||
app.showSpinner( panel );
|
||||
|
||||
// Load panel.
|
||||
$.post( wpforms_builder.ajax_url, {
|
||||
nonce: wpforms_builder.nonce,
|
||||
action: 'wpforms_builder_load_panel',
|
||||
panel,
|
||||
form_id: wpf.getQueryString( 'form_id' ), // eslint-disable-line camelcase
|
||||
} )
|
||||
.done( function( response ) {
|
||||
if ( ! response.success || ! response.data?.length ) {
|
||||
// Show an error message.
|
||||
app.displayErrorModal( `<p>${ wpforms_builder.error_load_templates }</p><p>${ wpforms_builder.error_contact_support }</p>` );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Append panel to the DOM.
|
||||
app.embedPanel( panel, response.data );
|
||||
|
||||
// Finalize switching to the panel.
|
||||
app.switchPanel( panel );
|
||||
|
||||
// Trigger panel loaded event.
|
||||
el.$builder.trigger( 'wpformsBuilderPanelLoaded', [ panel ] );
|
||||
} )
|
||||
.fail( function() {
|
||||
// Show an error message.
|
||||
app.displayErrorModal( `<p>${ wpforms_builder.something_went_wrong }.</p><p>${ wpforms_builder.error_contact_support }</p>` );
|
||||
} )
|
||||
.always( function() {
|
||||
// Hide loading spinner.
|
||||
app.hideSpinner( panel );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Show spinner.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} panel Panel name.
|
||||
*/
|
||||
showSpinner( panel ) {
|
||||
const $button = $( `.wpforms-panel-${ panel }-button` );
|
||||
|
||||
$button.find( `i.fa` ).addClass( 'wpforms-hidden' );
|
||||
$button.prepend( '<i class="wpforms-loading-spinner wpforms-loading-white"></i>' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide spinner.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} panel Panel name.
|
||||
*/
|
||||
hideSpinner( panel ) {
|
||||
const $button = $( `.wpforms-panel-${ panel }-button` );
|
||||
|
||||
$button.find( `i.fa` ).removeClass( 'wpforms-hidden' );
|
||||
$button.find( `i.wpforms-loading-spinner` ).remove();
|
||||
},
|
||||
|
||||
/**
|
||||
* Embed panel to DOM.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} panel Panel slug.
|
||||
* @param {string} panelHtml Panel HTML.
|
||||
*/
|
||||
embedPanel( panel, panelHtml ) {
|
||||
// Append panel to the DOM.
|
||||
el.$panels.append( panelHtml );
|
||||
},
|
||||
|
||||
/**
|
||||
* Finalize switching to the panel.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} panel Panel slug.
|
||||
*/
|
||||
switchPanel( panel ) {
|
||||
$( '#wpforms-panels-toggle' ).find( 'button' ).removeClass( 'active' );
|
||||
$( '.wpforms-panel' ).removeClass( 'active' );
|
||||
$( `.wpforms-panel-${ panel }-button` ).addClass( 'active' );
|
||||
$( `#wpforms-panel-${ panel }` ).addClass( 'active' );
|
||||
|
||||
history.replaceState( {}, null, wpf.updateQueryString( 'view', panel ) );
|
||||
|
||||
el.$builder.trigger( 'wpformsPanelSwitched', [ panel ] );
|
||||
},
|
||||
|
||||
/**
|
||||
* Display modal window with an error message.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} content Modal content.
|
||||
*/
|
||||
displayErrorModal( content ) {
|
||||
$.alert( {
|
||||
title : wpforms_builder.uh_oh,
|
||||
content,
|
||||
icon : 'fa fa-exclamation-circle',
|
||||
type : 'red',
|
||||
buttons: {
|
||||
cancel: {
|
||||
text : wpforms_builder.close,
|
||||
btnClass: 'btn-confirm',
|
||||
keys : [ 'enter' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPForms.Admin.Builder.PanelLoader.init();
|
||||
+1
@@ -0,0 +1 @@
|
||||
var WPForms=window.WPForms||{};WPForms.Admin=WPForms.Admin||{},WPForms.Admin.Builder=WPForms.Admin.Builder||{},WPForms.Admin.Builder.PanelLoader=WPForms.Admin.Builder.PanelLoader||(n=>{let o={},e=[],i={init(){n(i.ready)},ready(){i.setup(),i.events(),o.$builder.trigger("wpformsBuilderLoaderReady")},setup(){o.$builder=n("#wpforms-builder"),o.$form=n("#wpforms-builder-form"),o.$panels=o.$builder.find(".wpforms-panels"),e.currentPanel=wpf.getQueryString("view")},events(){o.$builder.on("wpformsPanelSwitch",function(e,r){o.$builder.find(`.wpforms-panel-${r}-button .wpforms-loading-spinner`).length?e.preventDefault():o.$panels.find("#wpforms-panel-"+r).length||(e.preventDefault(),i.loadPanel(r))})},loadPanel(r){i.showSpinner(r),n.post(wpforms_builder.ajax_url,{nonce:wpforms_builder.nonce,action:"wpforms_builder_load_panel",panel:r,form_id:wpf.getQueryString("form_id")}).done(function(e){e.success&&e.data?.length?(i.embedPanel(r,e.data),i.switchPanel(r),o.$builder.trigger("wpformsBuilderPanelLoaded",[r])):i.displayErrorModal(`<p>${wpforms_builder.error_load_templates}</p><p>${wpforms_builder.error_contact_support}</p>`)}).fail(function(){i.displayErrorModal(`<p>${wpforms_builder.something_went_wrong}.</p><p>${wpforms_builder.error_contact_support}</p>`)}).always(function(){i.hideSpinner(r)})},showSpinner(e){e=n(`.wpforms-panel-${e}-button`);e.find("i.fa").addClass("wpforms-hidden"),e.prepend('<i class="wpforms-loading-spinner wpforms-loading-white"></i>')},hideSpinner(e){e=n(`.wpforms-panel-${e}-button`);e.find("i.fa").removeClass("wpforms-hidden"),e.find("i.wpforms-loading-spinner").remove()},embedPanel(e,r){o.$panels.append(r)},switchPanel(e){n("#wpforms-panels-toggle").find("button").removeClass("active"),n(".wpforms-panel").removeClass("active"),n(`.wpforms-panel-${e}-button`).addClass("active"),n("#wpforms-panel-"+e).addClass("active"),history.replaceState({},null,wpf.updateQueryString("view",e)),o.$builder.trigger("wpformsPanelSwitched",[e])},displayErrorModal(e){n.alert({title:wpforms_builder.uh_oh,content:e,icon:"fa fa-exclamation-circle",type:"red",buttons:{cancel:{text:wpforms_builder.close,btnClass:"btn-confirm",keys:["enter"]}}})}};return i})((document,window,jQuery)),WPForms.Admin.Builder.PanelLoader.init();
|
||||
@@ -0,0 +1,119 @@
|
||||
/* global wpforms_builder, wpforms_builder_payments_utils */
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const WPFormsBuilderPaymentsUtils = window.WPFormsBuilderPaymentsUtils || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Toggle payments content.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*/
|
||||
// eslint-disable-next-line complexity
|
||||
toggleContent() {
|
||||
const $input = $( this ),
|
||||
$paymentSettings = $input.closest( '.wpforms-payment-settings' );
|
||||
|
||||
if (
|
||||
$paymentSettings.find( '.wpforms-panel-content-section-payment-toggle-one-time .wpforms-toggle-control > input' ).is( ':checked' ) &&
|
||||
$paymentSettings.find( '.wpforms-panel-content-section-payment-toggle-recurring .wpforms-toggle-control > input' ).is( ':checked' )
|
||||
) {
|
||||
$input.prop( 'checked', false );
|
||||
|
||||
$.alert( {
|
||||
title: wpforms_builder.heads_up,
|
||||
content: $input.attr( 'name' ).includes( 'enable_recurring' ) ? wpforms_builder_payments_utils.payments_disabled_recurring : wpforms_builder_payments_utils.payments_disabled_one_time,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_builder.ok,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
}
|
||||
|
||||
const $wrapper = $input.closest( '.wpforms-panel-content-section-payment' ),
|
||||
isChecked = $input.prop( 'checked' ) && ! $( '#wpforms-panel-field-settings-disable_entries' ).prop( 'checked' );
|
||||
|
||||
$wrapper.find( '.wpforms-panel-content-section-payment-toggled-body' ).toggle( isChecked );
|
||||
$wrapper.toggleClass( 'wpforms-panel-content-section-payment-open', isChecked );
|
||||
},
|
||||
|
||||
/**
|
||||
* Check a plan name on empty value.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*/
|
||||
checkPlanName() {
|
||||
const $input = $( this ),
|
||||
$plan = $input.closest( '.wpforms-panel-content-section-payment-plan' ),
|
||||
$planName = $plan.find( '.wpforms-panel-content-section-payment-plan-head-title' );
|
||||
|
||||
if ( $input.val() ) {
|
||||
$planName.html( $input.val() );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const defaultValue = wpforms_builder_payments_utils.payments_plan_placeholder;
|
||||
|
||||
$planName.html( defaultValue );
|
||||
$input.val( defaultValue );
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle a plan content.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*/
|
||||
togglePlan() {
|
||||
const $plan = $( this ).closest( '.wpforms-panel-content-section-payment-plan' ),
|
||||
$icon = $plan.find( '.wpforms-panel-content-section-payment-plan-head-buttons-toggle' );
|
||||
|
||||
$icon.toggleClass( 'fa-chevron-circle-up fa-chevron-circle-down' );
|
||||
$plan.find( '.wpforms-panel-content-section-payment-plan-body' ).toggle( $icon.hasClass( 'fa-chevron-circle-down' ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* Delete a plan.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*/
|
||||
deletePlan() {
|
||||
// Trigger a warning modal when trying to delete a single plan without pro addon.
|
||||
$( this ).closest( '.wpforms-panel-content-section-payment' ).find( '.wpforms-panel-content-section-payment-button-add-plan' ).trigger( 'click' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Rename a plan.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*/
|
||||
renamePlan() {
|
||||
const $input = $( this ),
|
||||
$plan = $input.closest( '.wpforms-panel-content-section-payment-plan' ),
|
||||
$planName = $plan.find( '.wpforms-panel-content-section-payment-plan-head-title' );
|
||||
|
||||
if ( ! $input.val() ) {
|
||||
$planName.html( '' );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$planName.html( $input.val() );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
+1
@@ -0,0 +1 @@
|
||||
let WPFormsBuilderPaymentsUtils=window.WPFormsBuilderPaymentsUtils||(o=>({toggleContent(){var e=o(this),n=e.closest(".wpforms-payment-settings"),n=(n.find(".wpforms-panel-content-section-payment-toggle-one-time .wpforms-toggle-control > input").is(":checked")&&n.find(".wpforms-panel-content-section-payment-toggle-recurring .wpforms-toggle-control > input").is(":checked")&&(e.prop("checked",!1),o.alert({title:wpforms_builder.heads_up,content:e.attr("name").includes("enable_recurring")?wpforms_builder_payments_utils.payments_disabled_recurring:wpforms_builder_payments_utils.payments_disabled_one_time,icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"]}}})),e.closest(".wpforms-panel-content-section-payment")),e=e.prop("checked")&&!o("#wpforms-panel-field-settings-disable_entries").prop("checked");n.find(".wpforms-panel-content-section-payment-toggled-body").toggle(e),n.toggleClass("wpforms-panel-content-section-payment-open",e)},checkPlanName(){var e,n=o(this),t=n.closest(".wpforms-panel-content-section-payment-plan").find(".wpforms-panel-content-section-payment-plan-head-title");n.val()?t.html(n.val()):(e=wpforms_builder_payments_utils.payments_plan_placeholder,t.html(e),n.val(e))},togglePlan(){var e=o(this).closest(".wpforms-panel-content-section-payment-plan"),n=e.find(".wpforms-panel-content-section-payment-plan-head-buttons-toggle");n.toggleClass("fa-chevron-circle-up fa-chevron-circle-down"),e.find(".wpforms-panel-content-section-payment-plan-body").toggle(n.hasClass("fa-chevron-circle-down"))},deletePlan(){o(this).closest(".wpforms-panel-content-section-payment").find(".wpforms-panel-content-section-payment-button-add-plan").trigger("click")},renamePlan(){var e=o(this),n=e.closest(".wpforms-panel-content-section-payment-plan").find(".wpforms-panel-content-section-payment-plan-head-title");e.val()?n.html(e.val()):n.html("")}}))((document,window,jQuery));
|
||||
File diff suppressed because it is too large
Load Diff
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,207 @@
|
||||
/**
|
||||
* WPForms Builder Search module.
|
||||
*
|
||||
* @since 1.8.3
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var WPForms = window.WPForms || {};
|
||||
|
||||
WPForms.Admin = WPForms.Admin || {};
|
||||
WPForms.Admin.Builder = WPForms.Admin.Builder || {};
|
||||
|
||||
WPForms.Admin.Builder.Search = WPForms.Admin.Builder.Search || ( function( document, window, $ ) {
|
||||
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.8.3
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
const el = {};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.8.3
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine. DOM is not ready yet, use only to init something.
|
||||
*
|
||||
* @since 1.8.3
|
||||
*/
|
||||
init: function() {
|
||||
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* DOM is fully loaded.
|
||||
*
|
||||
* @since 1.8.3
|
||||
*/
|
||||
ready: function() {
|
||||
|
||||
app.setup();
|
||||
app.events();
|
||||
app.scrollSidebar();
|
||||
},
|
||||
|
||||
/**
|
||||
* Scroll the sidebar to the height of the search.
|
||||
*
|
||||
* @since 1.8.3
|
||||
*/
|
||||
scrollSidebar: function() {
|
||||
|
||||
el.$sidebar.scrollTop( el.$searchWrapper.height() + 20 );
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup. Prepare some variables.
|
||||
*
|
||||
* @since 1.8.3
|
||||
*/
|
||||
setup: function() {
|
||||
|
||||
// Cache DOM elements
|
||||
el.$document = $( document );
|
||||
el.$builder = $( '#wpforms-builder' );
|
||||
el.$searchInput = $( '#wpforms-search-fields-input' );
|
||||
el.$searchInputCloseBtn = $( '.wpforms-search-fields-input-close' );
|
||||
el.$searchWrapper = $( '.wpforms-search-fields-wrapper' );
|
||||
el.$noResults = $( '.wpforms-search-fields-no-results' );
|
||||
el.$listWrapper = $( '.wpforms-search-fields-list' );
|
||||
el.$list = $( '.wpforms-search-fields-list .wpforms-add-fields-buttons' );
|
||||
el.$groups = $( '.wpforms-tab-content > .wpforms-add-fields-group' );
|
||||
el.$sidebar = $( '#wpforms-panel-fields .wpforms-add-fields' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events.
|
||||
*
|
||||
* @since 1.8.3
|
||||
*/
|
||||
events: function() {
|
||||
|
||||
el.$searchInput.on( 'keyup', app.searchAction );
|
||||
el.$searchInputCloseBtn.on( 'click', app.clearSearch );
|
||||
el.$document.on( 'wpformsFieldAdd', app.clearSearch );
|
||||
el.$document.on( 'wpformsFieldDelete', app.refreshSearchResults );
|
||||
},
|
||||
|
||||
/**
|
||||
* Search action.
|
||||
*
|
||||
* @since 1.8.3
|
||||
*/
|
||||
searchAction: function() {
|
||||
|
||||
const $fields = el.$builder.find( '.wpforms-tab-content > .wpforms-add-fields-group .wpforms-add-fields-button' );
|
||||
const searchValue = el.$searchInput.val().toLowerCase();
|
||||
|
||||
el.$list.empty();
|
||||
|
||||
if ( searchValue ) {
|
||||
el.$groups.hide();
|
||||
el.$listWrapper.show();
|
||||
el.$searchInputCloseBtn.addClass( 'active' );
|
||||
|
||||
$fields.each( function() {
|
||||
|
||||
const $item = $( this );
|
||||
const titleText = $item.text().toLowerCase();
|
||||
const keywords = $item.data( 'field-keywords' ) ? $item.data( 'field-keywords' ).toLowerCase() : '';
|
||||
|
||||
if ( titleText.indexOf( searchValue ) >= 0 || ( keywords && keywords.indexOf( searchValue ) >= 0 ) ) {
|
||||
const $clone = $item.clone();
|
||||
|
||||
$clone.attr( 'data-target', $clone.attr( 'id' ) );
|
||||
$clone.removeAttr( 'id' );
|
||||
$clone.addClass( 'wpforms-add-fields-button-clone' );
|
||||
|
||||
el.$list.append( $clone );
|
||||
}
|
||||
} );
|
||||
|
||||
const $matchingItems = el.$list.find( '.wpforms-add-fields-button' );
|
||||
const hasMatchingItems = $matchingItems.length > 0;
|
||||
|
||||
if ( hasMatchingItems ) {
|
||||
el.$noResults.hide();
|
||||
} else {
|
||||
el.$noResults.show();
|
||||
el.$listWrapper.hide();
|
||||
}
|
||||
} else {
|
||||
el.$groups.show();
|
||||
el.$listWrapper.hide();
|
||||
el.$noResults.hide();
|
||||
el.$searchInputCloseBtn.removeClass( 'active' );
|
||||
}
|
||||
|
||||
WPForms.Admin.Builder.DragFields.setup();
|
||||
WPForms.Admin.Builder.DragFields.initSortableFields();
|
||||
app.cloneClickAction();
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear search.
|
||||
*
|
||||
* @since 1.8.3
|
||||
*/
|
||||
clearSearch: function() {
|
||||
|
||||
if ( ! el.$searchInput.val() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
el.$list.empty();
|
||||
el.$listWrapper.hide();
|
||||
el.$groups.show();
|
||||
el.$noResults.hide();
|
||||
el.$searchInput.val( '' ).focus();
|
||||
el.$searchInputCloseBtn.removeClass( 'active' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Refresh search results.
|
||||
*
|
||||
* @since 1.8.3
|
||||
*/
|
||||
refreshSearchResults: function() {
|
||||
|
||||
// We need to wait for the original field to be unlocked.
|
||||
setTimeout( app.searchAction, 0 );
|
||||
},
|
||||
|
||||
/**
|
||||
* Clone click action.
|
||||
*
|
||||
* @since 1.8.3
|
||||
*/
|
||||
cloneClickAction() {
|
||||
$( '.wpforms-add-fields-button-clone' ).on( 'click', function( e ) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const target = $( this ).attr( 'data-target' );
|
||||
|
||||
$( '#' + target ).trigger( 'click' );
|
||||
} );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPForms.Admin.Builder.Search.init();
|
||||
+1
@@ -0,0 +1 @@
|
||||
var WPForms=window.WPForms||{};WPForms.Admin=WPForms.Admin||{},WPForms.Admin.Builder=WPForms.Admin.Builder||{},WPForms.Admin.Builder.Search=WPForms.Admin.Builder.Search||((e,o)=>{let i={},s={init:function(){o(s.ready)},ready:function(){s.setup(),s.events(),s.scrollSidebar()},scrollSidebar:function(){i.$sidebar.scrollTop(i.$searchWrapper.height()+20)},setup:function(){i.$document=o(e),i.$builder=o("#wpforms-builder"),i.$searchInput=o("#wpforms-search-fields-input"),i.$searchInputCloseBtn=o(".wpforms-search-fields-input-close"),i.$searchWrapper=o(".wpforms-search-fields-wrapper"),i.$noResults=o(".wpforms-search-fields-no-results"),i.$listWrapper=o(".wpforms-search-fields-list"),i.$list=o(".wpforms-search-fields-list .wpforms-add-fields-buttons"),i.$groups=o(".wpforms-tab-content > .wpforms-add-fields-group"),i.$sidebar=o("#wpforms-panel-fields .wpforms-add-fields")},events:function(){i.$searchInput.on("keyup",s.searchAction),i.$searchInputCloseBtn.on("click",s.clearSearch),i.$document.on("wpformsFieldAdd",s.clearSearch),i.$document.on("wpformsFieldDelete",s.refreshSearchResults)},searchAction:function(){var e=i.$builder.find(".wpforms-tab-content > .wpforms-add-fields-group .wpforms-add-fields-button");let t=i.$searchInput.val().toLowerCase();i.$list.empty(),t?(i.$groups.hide(),i.$listWrapper.show(),i.$searchInputCloseBtn.addClass("active"),e.each(function(){var e=o(this),s=e.text().toLowerCase(),r=e.data("field-keywords")?e.data("field-keywords").toLowerCase():"";(0<=s.indexOf(t)||r&&0<=r.indexOf(t))&&((s=e.clone()).attr("data-target",s.attr("id")),s.removeAttr("id"),s.addClass("wpforms-add-fields-button-clone"),i.$list.append(s))}),(0<i.$list.find(".wpforms-add-fields-button").length?i.$noResults:(i.$noResults.show(),i.$listWrapper)).hide()):(i.$groups.show(),i.$listWrapper.hide(),i.$noResults.hide(),i.$searchInputCloseBtn.removeClass("active")),WPForms.Admin.Builder.DragFields.setup(),WPForms.Admin.Builder.DragFields.initSortableFields(),s.cloneClickAction()},clearSearch:function(){i.$searchInput.val()&&(i.$list.empty(),i.$listWrapper.hide(),i.$groups.show(),i.$noResults.hide(),i.$searchInput.val("").focus(),i.$searchInputCloseBtn.removeClass("active"))},refreshSearchResults:function(){setTimeout(s.searchAction,0)},cloneClickAction(){o(".wpforms-add-fields-button-clone").on("click",function(e){e.preventDefault(),e.stopPropagation();e=o(this).attr("data-target");o("#"+e).trigger("click")})}};return s})(document,(window,jQuery)),WPForms.Admin.Builder.Search.init();
|
||||
@@ -0,0 +1,453 @@
|
||||
/* global wpforms_builder_settings, Choices, wpforms_builder */
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
/**
|
||||
* Form Builder Settings Panel module.
|
||||
*
|
||||
* @since 1.7.5
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
var WPForms = window.WPForms || {};
|
||||
|
||||
WPForms.Admin = WPForms.Admin || {};
|
||||
WPForms.Admin.Builder = WPForms.Admin.Builder || {};
|
||||
|
||||
WPForms.Admin.Builder.Settings = WPForms.Admin.Builder.Settings || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.7.5
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
let el = {};
|
||||
|
||||
/**
|
||||
* Runtime variables.
|
||||
*
|
||||
* @since 1.7.5
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const vars = {};
|
||||
|
||||
// noinspection JSUnusedLocalSymbols,ES6ConvertVarToLetConst
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.7.5
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
// eslint-disable-next-line no-var
|
||||
var app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.7.5
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* DOM is fully loaded.
|
||||
*
|
||||
* @since 1.7.5
|
||||
*/
|
||||
ready() {
|
||||
app.setup();
|
||||
app.initTags();
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup. Prepare some variables.
|
||||
*
|
||||
* @since 1.7.5
|
||||
*/
|
||||
setup() {
|
||||
// Cache DOM elements.
|
||||
el = {
|
||||
$builder: $( '#wpforms-builder' ),
|
||||
$panel: $( '#wpforms-panel-settings' ),
|
||||
$selectTags: $( '#wpforms-panel-field-settings-form_tags' ),
|
||||
};
|
||||
|
||||
// Give a chance to interact with "Disable entry..." option immediately.
|
||||
app.allowEditDisabledEntriesOption();
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events.
|
||||
*
|
||||
* @since 1.7.5
|
||||
*/
|
||||
events() {
|
||||
el.$panel
|
||||
.on( 'keydown', '#wpforms-panel-field-settings-form_tags-wrap input', app.addCustomTagInput )
|
||||
.on( 'removeItem', '#wpforms-panel-field-settings-form_tags-wrap select', app.editTagsRemoveItem )
|
||||
.on( 'change', '#wpforms-panel-field-settings-antispam_v3', app.enableAntispamV3 )
|
||||
.on( 'change', '#wpforms-panel-field-settings-disable_entries', app.disableEntries )
|
||||
.on( 'change', '#wpforms-panel-field-settings-store_spam_entries', app.storeSpamEntries );
|
||||
|
||||
el.$selectTags
|
||||
.on( 'change', app.changeTags );
|
||||
|
||||
$( document ).on( 'connectionsDataLoaded', app.allowEditDisabledEntriesOption );
|
||||
},
|
||||
|
||||
/**
|
||||
* Enable Anti spam v3 toggle change event.
|
||||
*
|
||||
* @since 1.9.0
|
||||
*/
|
||||
enableAntispamV3() {
|
||||
// Hide and disable old anti-spam.
|
||||
$( '#wpforms-panel-field-settings-antispam' )
|
||||
.prop( 'checked', false )
|
||||
.closest( '.wpforms-panel-field' )
|
||||
.toggleClass( 'wpforms-hidden' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Disable Entries toggle change event.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*/
|
||||
disableEntries() {
|
||||
const $this = $( this );
|
||||
const isChecked = $this.prop( 'checked' );
|
||||
const isStoreSpamEntriesChecked = $( '#wpforms-panel-field-settings-store_spam_entries' ).prop( 'checked' );
|
||||
|
||||
app.toggleFilteringMessages( ! isChecked && isStoreSpamEntriesChecked );
|
||||
// Toggle the store spam entries toggle.
|
||||
$( '#wpforms-panel-field-settings-store_spam_entries-wrap' ).toggleClass( 'wpforms-hidden', $this.prop( 'checked' ) );
|
||||
|
||||
if ( ! $this.prop( 'checked' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const entryRequirement = app.getEntryRequirement();
|
||||
|
||||
// Don't allow users to disable entries if some third-party integrations
|
||||
// require it.
|
||||
if ( entryRequirement.required ) {
|
||||
$.confirm( {
|
||||
title: wpforms_builder.entry_storage_required,
|
||||
content: app.getDisabledEntryMessage( entryRequirement ),
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_builder.ok,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
$this.prop( 'checked', false );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$.alert( {
|
||||
title: wpforms_builder.heads_up,
|
||||
content: wpforms_builder.disable_entries,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_builder.ok,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Store Spam Entries toggle change event.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*/
|
||||
storeSpamEntries() {
|
||||
app.toggleFilteringMessages( $( this ).prop( 'checked' ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle Filtering Messages.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*
|
||||
* @param {boolean} $hide Whether to hide or show messages.
|
||||
*/
|
||||
toggleFilteringMessages( $hide ) {
|
||||
if ( ! $( '#wpforms-panel-field-anti_spam-filtering_store_spam' ).is( ':checked' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Toggle Country Filter Message.
|
||||
$( '#wpforms-panel-field-anti_spam-country_filter-message-wrap' ).toggleClass( 'wpforms-hidden', $hide );
|
||||
|
||||
// Toggle Keyywords Filter Message.
|
||||
$( '#wpforms-panel-field-anti_spam-keyword_filter-message-wrap' ).toggleClass( 'wpforms-hidden', $hide );
|
||||
},
|
||||
|
||||
/**
|
||||
* Init Choices.js on the Tags select an input element.
|
||||
*
|
||||
* @param {Object} $el Element.
|
||||
* @since 1.7.5
|
||||
*/
|
||||
initTags( $el = null ) {
|
||||
$el = $el?.length ? $el : el.$selectTags;
|
||||
|
||||
// Skip in certain cases.
|
||||
if (
|
||||
! $el.length ||
|
||||
typeof window.Choices !== 'function'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Init Choices.js object instance.
|
||||
vars.tagsChoicesObj = new Choices( $el[ 0 ], wpforms_builder_settings.choicesjs_config );
|
||||
|
||||
// Backup current value.
|
||||
const currentValue = vars.tagsChoicesObj.getValue( true );
|
||||
|
||||
// Update all tags choices.
|
||||
vars.tagsChoicesObj
|
||||
.clearStore()
|
||||
.setChoices(
|
||||
wpforms_builder_settings.all_tags_choices,
|
||||
'value',
|
||||
'label',
|
||||
true
|
||||
)
|
||||
.setChoiceByValue( currentValue );
|
||||
|
||||
$el.data( 'choicesjs', vars.tagsChoicesObj );
|
||||
|
||||
app.initTagsHiddenInput();
|
||||
},
|
||||
|
||||
/**
|
||||
* Init Tags hidden input element.
|
||||
*
|
||||
* @since 1.7.5
|
||||
*/
|
||||
initTagsHiddenInput() {
|
||||
// Create additional hidden input.
|
||||
el.$selectTagsHiddenInput = $( '<input type="hidden" name="settings[form_tags_json]">' );
|
||||
el.$selectTags
|
||||
.closest( '.wpforms-panel-field' )
|
||||
.append( el.$selectTagsHiddenInput );
|
||||
|
||||
// Update hidden input value.
|
||||
app.changeTags( null );
|
||||
},
|
||||
|
||||
/**
|
||||
* Add custom item to Tags dropdown on input.
|
||||
*
|
||||
* @since 1.7.5
|
||||
*
|
||||
* @param {Object} event Event object.
|
||||
*/
|
||||
addCustomTagInput( event ) {
|
||||
if ( [ 'Enter', ',' ].indexOf( event.key ) < 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
if ( ! vars.tagsChoicesObj || event.target.value.length === 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tagLabel = _.escape( event.target.value ).trim(),
|
||||
labels = _.map( vars.tagsChoicesObj.getValue(), 'label' ).map( function( label ) {
|
||||
return label.toLowerCase().trim();
|
||||
} );
|
||||
|
||||
if ( tagLabel === '' || labels.indexOf( tagLabel.toLowerCase() ) >= 0 ) {
|
||||
vars.tagsChoicesObj.clearInput();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
app.addCustomTagInputCreate( tagLabel );
|
||||
app.changeTags( event );
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove tag from Tags field event handler.
|
||||
*
|
||||
* @since 1.7.5
|
||||
*
|
||||
* @param {Object} event Event object.
|
||||
*/
|
||||
editTagsRemoveItem( event ) {
|
||||
const allValues = _.map( wpforms_builder_settings.all_tags_choices, 'value' );
|
||||
|
||||
if ( allValues.indexOf( event.detail.value ) >= 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We should remove new tag from the list of choices.
|
||||
const choicesObj = $( event.target ).data( 'choicesjs' ),
|
||||
currentValue = choicesObj.getValue( true ),
|
||||
choices = _.filter( choicesObj._currentState.choices, function( item ) {
|
||||
return item.value !== event.detail.value;
|
||||
} );
|
||||
|
||||
choicesObj
|
||||
.clearStore()
|
||||
.setChoices( choices, 'value', 'label', true )
|
||||
.setChoiceByValue( currentValue );
|
||||
},
|
||||
|
||||
/**
|
||||
* Add custom item to Tags dropdown on input (second part).
|
||||
*
|
||||
* @since 1.7.5
|
||||
*
|
||||
* @param {Object} tagLabel Event object.
|
||||
*/
|
||||
addCustomTagInputCreate( tagLabel ) {
|
||||
const tag = _.find( wpforms_builder_settings.all_tags_choices, { label: tagLabel } );
|
||||
|
||||
if ( tag && tag.value ) {
|
||||
vars.tagsChoicesObj.setChoiceByValue( tag.value );
|
||||
} else {
|
||||
vars.tagsChoicesObj.setChoices(
|
||||
[
|
||||
{
|
||||
value: tagLabel,
|
||||
label: tagLabel,
|
||||
selected: true,
|
||||
},
|
||||
],
|
||||
'value',
|
||||
'label',
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
vars.tagsChoicesObj.clearInput();
|
||||
},
|
||||
|
||||
/**
|
||||
* Change Tags field event handler.
|
||||
*
|
||||
* @since 1.7.5
|
||||
*
|
||||
* @param {Object} event Event object.
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
changeTags( event ) {
|
||||
const tagsValue = vars.tagsChoicesObj.getValue(),
|
||||
tags = [];
|
||||
|
||||
for ( let i = 0; i < tagsValue.length; i++ ) {
|
||||
tags.push( {
|
||||
value: tagsValue[ i ].value,
|
||||
label: tagsValue[ i ].label,
|
||||
} );
|
||||
}
|
||||
|
||||
// Update Tags field hidden input value.
|
||||
el.$selectTagsHiddenInput.val(
|
||||
JSON.stringify( tags )
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Generates a message to indicate why certain entries are disabled,
|
||||
* including necessary dependencies for enabling them.
|
||||
*
|
||||
* @since 1.9.6
|
||||
*
|
||||
* @param {Object} entryRequirement An object containing details about the requirements.
|
||||
*
|
||||
* @return {string} The customized message indicating why the entries are disabled.
|
||||
*/
|
||||
getDisabledEntryMessage( entryRequirement ) {
|
||||
const dependencies = entryRequirement?.dependencies || {};
|
||||
|
||||
if ( ! Object.keys( dependencies ).length ) {
|
||||
return wpforms_builder.payments_on_entries_off;
|
||||
}
|
||||
|
||||
const dependenciesHTML = Object.values( dependencies ).map( ( { text, href }, index, arr ) => {
|
||||
const linkHTML = `<a href="${ href }" target="_blank">${ text }</a>`;
|
||||
|
||||
if ( index === arr.length - 1 && arr.length > 1 ) {
|
||||
// The very last item when array has multiple items, prepend with "and".
|
||||
return `and ${ linkHTML }`;
|
||||
} else if ( index < arr.length - 2 ) {
|
||||
// Any item except the last two, append comma.
|
||||
return `${ linkHTML },`;
|
||||
}
|
||||
|
||||
// Second-to-last item, no comma needed as next item will prepend "and".
|
||||
return linkHTML;
|
||||
} ).join( ' ' );
|
||||
|
||||
return wpforms_builder.payments_on_entries_off.replace( '{integration}', dependenciesHTML );
|
||||
},
|
||||
|
||||
/**
|
||||
* Allows interacting with the option for disabled entries in the WPForms settings panel.
|
||||
* This method ensures that the entry requirement is met before enabling the option.
|
||||
* If some providers or gateways are still loading, the process is aborted.
|
||||
*
|
||||
* @since 1.9.6
|
||||
*/
|
||||
allowEditDisabledEntriesOption() {
|
||||
const $toggleSpan = $( '#wpforms-panel-field-settings-disable_entries-wrap > span' );
|
||||
|
||||
if ( ! $toggleSpan.hasClass( 'wpforms-toggle-control-disabled' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const entryRequirement = app.getEntryRequirement();
|
||||
|
||||
if ( entryRequirement?.loadingStack?.size ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$toggleSpan.removeClass( 'wpforms-toggle-control-disabled' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Allows modifying the entry requirement configuration, including whether
|
||||
* the entry is required and any dependencies associated with it.
|
||||
*
|
||||
* @since 1.9.6
|
||||
*
|
||||
* @property {boolean} required Indicates whether the entry is required.
|
||||
* @property {Object} dependencies Specifies dependencies for the entry. See app.getDisabledEntryMessage for more details.
|
||||
* @property {Set} loadingStack A set used to manage loading states.
|
||||
*
|
||||
* @return {Object} The entry requirement object.
|
||||
*/
|
||||
getEntryRequirement() {
|
||||
return wp.hooks.applyFilters(
|
||||
'wpforms.Builder.entryRequirement',
|
||||
{ required: false, dependencies: {}, loadingStack: new Set() }
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPForms.Admin.Builder.Settings.init();
|
||||
+1
@@ -0,0 +1 @@
|
||||
var WPForms=window.WPForms||{};WPForms.Admin=WPForms.Admin||{},WPForms.Admin.Builder=WPForms.Admin.Builder||{},WPForms.Admin.Builder.Settings=WPForms.Admin.Builder.Settings||((e,s,n)=>{let a={},i={};var r={init(){n(r.ready)},ready(){r.setup(),r.initTags(),r.events()},setup(){a={$builder:n("#wpforms-builder"),$panel:n("#wpforms-panel-settings"),$selectTags:n("#wpforms-panel-field-settings-form_tags")},r.allowEditDisabledEntriesOption()},events(){a.$panel.on("keydown","#wpforms-panel-field-settings-form_tags-wrap input",r.addCustomTagInput).on("removeItem","#wpforms-panel-field-settings-form_tags-wrap select",r.editTagsRemoveItem).on("change","#wpforms-panel-field-settings-antispam_v3",r.enableAntispamV3).on("change","#wpforms-panel-field-settings-disable_entries",r.disableEntries).on("change","#wpforms-panel-field-settings-store_spam_entries",r.storeSpamEntries),a.$selectTags.on("change",r.changeTags),n(e).on("connectionsDataLoaded",r.allowEditDisabledEntriesOption)},enableAntispamV3(){n("#wpforms-panel-field-settings-antispam").prop("checked",!1).closest(".wpforms-panel-field").toggleClass("wpforms-hidden")},disableEntries(){var e=n(this),t=e.prop("checked"),s=n("#wpforms-panel-field-settings-store_spam_entries").prop("checked");r.toggleFilteringMessages(!t&&s),n("#wpforms-panel-field-settings-store_spam_entries-wrap").toggleClass("wpforms-hidden",e.prop("checked")),e.prop("checked")&&((t=r.getEntryRequirement()).required?(n.confirm({title:wpforms_builder.entry_storage_required,content:r.getDisabledEntryMessage(t),icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"]}}}),e.prop("checked",!1)):n.alert({title:wpforms_builder.heads_up,content:wpforms_builder.disable_entries,icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"]}}}))},storeSpamEntries(){r.toggleFilteringMessages(n(this).prop("checked"))},toggleFilteringMessages(e){n("#wpforms-panel-field-anti_spam-filtering_store_spam").is(":checked")&&(n("#wpforms-panel-field-anti_spam-country_filter-message-wrap").toggleClass("wpforms-hidden",e),n("#wpforms-panel-field-anti_spam-keyword_filter-message-wrap").toggleClass("wpforms-hidden",e))},initTags(e=null){var t;(e=e?.length?e:a.$selectTags).length&&"function"==typeof s.Choices&&(i.tagsChoicesObj=new Choices(e[0],wpforms_builder_settings.choicesjs_config),t=i.tagsChoicesObj.getValue(!0),i.tagsChoicesObj.clearStore().setChoices(wpforms_builder_settings.all_tags_choices,"value","label",!0).setChoiceByValue(t),e.data("choicesjs",i.tagsChoicesObj),r.initTagsHiddenInput())},initTagsHiddenInput(){a.$selectTagsHiddenInput=n('<input type="hidden" name="settings[form_tags_json]">'),a.$selectTags.closest(".wpforms-panel-field").append(a.$selectTagsHiddenInput),r.changeTags(null)},addCustomTagInput(e){var t,s;["Enter",","].indexOf(e.key)<0||(e.preventDefault(),e.stopPropagation(),i.tagsChoicesObj&&0!==e.target.value.length&&(t=_.escape(e.target.value).trim(),s=_.map(i.tagsChoicesObj.getValue(),"label").map(function(e){return e.toLowerCase().trim()}),""===t||0<=s.indexOf(t.toLowerCase())?i.tagsChoicesObj.clearInput():(r.addCustomTagInputCreate(t),r.changeTags(e))))},editTagsRemoveItem(t){var e,s,a;0<=_.map(wpforms_builder_settings.all_tags_choices,"value").indexOf(t.detail.value)||(s=(e=n(t.target).data("choicesjs")).getValue(!0),a=_.filter(e._currentState.choices,function(e){return e.value!==t.detail.value}),e.clearStore().setChoices(a,"value","label",!0).setChoiceByValue(s))},addCustomTagInputCreate(e){var t=_.find(wpforms_builder_settings.all_tags_choices,{label:e});t&&t.value?i.tagsChoicesObj.setChoiceByValue(t.value):i.tagsChoicesObj.setChoices([{value:e,label:e,selected:!0}],"value","label",!1),i.tagsChoicesObj.clearInput()},changeTags(e){var t=i.tagsChoicesObj.getValue(),s=[];for(let e=0;e<t.length;e++)s.push({value:t[e].value,label:t[e].label});a.$selectTagsHiddenInput.val(JSON.stringify(s))},getDisabledEntryMessage(e){var e=e?.dependencies||{};return Object.keys(e).length?(e=Object.values(e).map(({text:e,href:t},s,a)=>{t=`<a href="${t}" target="_blank">${e}</a>`;return s===a.length-1&&1<a.length?"and "+t:s<a.length-2?t+",":t}).join(" "),wpforms_builder.payments_on_entries_off.replace("{integration}",e)):wpforms_builder.payments_on_entries_off},allowEditDisabledEntriesOption(){var e=n("#wpforms-panel-field-settings-disable_entries-wrap > span");e.hasClass("wpforms-toggle-control-disabled")&&!r.getEntryRequirement()?.loadingStack?.size&&e.removeClass("wpforms-toggle-control-disabled")},getEntryRequirement(){return wp.hooks.applyFilters("wpforms.Builder.entryRequirement",{required:!1,dependencies:{},loadingStack:new Set})}};return r})(document,window,jQuery),WPForms.Admin.Builder.Settings.init();
|
||||
@@ -0,0 +1,749 @@
|
||||
/* global wpforms_builder, wpf, WPFormsBuilder, WPFormsFormTemplates */
|
||||
/* eslint-disable no-console */
|
||||
|
||||
/**
|
||||
* @param wpforms_builder.blank_form
|
||||
* @param wpforms_builder.error_select_template
|
||||
* @param wpforms_builder.form_meta
|
||||
* @param wpforms_builder.template_confirm
|
||||
* @param wpforms_builder.use_default_template
|
||||
*/
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
/**
|
||||
* Form Builder Setup Panel module.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*/
|
||||
|
||||
var WPForms = window.WPForms || {}; // eslint-disable-line no-var
|
||||
|
||||
WPForms.Admin = WPForms.Admin || {};
|
||||
WPForms.Admin.Builder = WPForms.Admin.Builder || {};
|
||||
|
||||
WPForms.Admin.Builder.Setup = WPForms.Admin.Builder.Setup || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const el = {};
|
||||
|
||||
/**
|
||||
* Runtime variables.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const vars = {};
|
||||
|
||||
/**
|
||||
* Active template name.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*/
|
||||
const activeTemplateName = $( '.wpforms-template.selected .wpforms-template-name' ).text().trim();
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
|
||||
// Page load.
|
||||
$( window ).on( 'load', function() {
|
||||
// In the case of jQuery 3.+, we need to wait for a ready event first.
|
||||
if ( typeof $.ready.then === 'function' ) {
|
||||
$.ready.then( app.load );
|
||||
} else {
|
||||
app.load();
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* DOM is fully loaded.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*/
|
||||
ready() {
|
||||
app.setup();
|
||||
app.setPanelsToggleState();
|
||||
app.setupTitleFocus();
|
||||
app.setTriggerBlankLink();
|
||||
app.events();
|
||||
|
||||
// Trigger `wpformsBuilderPanelLoaded` event only when the panel is available in DOM.
|
||||
if ( el.$panel.length ) {
|
||||
el.$builder.trigger( 'wpformsBuilderPanelLoaded', [ 'setup' ] );
|
||||
}
|
||||
|
||||
el.$builder.trigger( 'wpformsBuilderSetupReady' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Page load.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*/
|
||||
load() {
|
||||
app.applyTemplateOnRequest();
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup. Prepare some variables.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*/
|
||||
setup() {
|
||||
// Cache DOM elements.
|
||||
el.$builder = $( '#wpforms-builder' );
|
||||
el.$form = $( '#wpforms-builder-form' );
|
||||
el.$formName = $( '#wpforms-setup-name' );
|
||||
el.$panel = $( '#wpforms-panel-setup' );
|
||||
el.$categories = $( '#wpforms-panel-setup .wpforms-setup-templates-categories' );
|
||||
el.$subcategories = $( '#wpforms-panel-setup .wpforms-setup-templates-subcategories' );
|
||||
|
||||
// Other values.
|
||||
vars.spinner = '<i class="wpforms-loading-spinner wpforms-loading-white wpforms-loading-inline"></i>';
|
||||
vars.formID = el.$form.data( 'id' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*/
|
||||
events() {
|
||||
el.$builder.on( 'wpformsBuilderPanelLoaded', app.panelLoaded );
|
||||
|
||||
// Focus on the form title field when displaying a setup panel.
|
||||
el.$builder
|
||||
.on( 'wpformsPanelSwitched', app.setupTitleFocus );
|
||||
|
||||
// Sync Setup title and settings title.
|
||||
el.$builder
|
||||
.on( 'input', '#wpforms-panel-field-settings-form_title', app.syncTitle )
|
||||
.on( 'input', '#wpforms-setup-name', app.syncTitle );
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind panel events.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
panelEvents() {
|
||||
el.$panel
|
||||
.on( 'keyup', '#wpforms-setup-template-search', _.debounce( WPFormsFormTemplates.searchTemplate, 200 ) )
|
||||
.on( 'click', '.wpforms-setup-templates-categories li div', WPFormsFormTemplates.selectCategory )
|
||||
.on( 'click', '.wpforms-setup-templates-categories li .chevron', WPFormsFormTemplates.toggleSubcategoriesList )
|
||||
.on( 'click', '.wpforms-setup-templates-subcategories li', WPFormsFormTemplates.selectSubCategory )
|
||||
.on( 'click', '.wpforms-template-select', app.selectTemplate )
|
||||
.on( 'click', '.wpforms-trigger-blank', app.selectBlankTemplate );
|
||||
|
||||
el.$builder
|
||||
.on( 'wpformsBuilderReady wpformsBuilderPanelLoaded', app.filterTemplatesBySelectedCategory );
|
||||
},
|
||||
|
||||
/**
|
||||
* Panel loaded event.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
* @param {string} panel Panel name.
|
||||
*/
|
||||
panelLoaded( e, panel ) {
|
||||
if ( panel !== 'setup' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
WPFormsFormTemplates.setup();
|
||||
app.setup();
|
||||
app.setSelectedTemplate();
|
||||
app.setSelectedCategories();
|
||||
app.panelEvents();
|
||||
},
|
||||
|
||||
/**
|
||||
* Set panels toggle buttons state.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*/
|
||||
setPanelsToggleState() {
|
||||
el.$builder
|
||||
.find( '#wpforms-panels-toggle button:not(.active)' )
|
||||
.toggleClass( 'wpforms-disabled', vars.formID === '' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Set attributes of "blank template" link.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*/
|
||||
setTriggerBlankLink() {
|
||||
el.$builder
|
||||
.find( '.wpforms-trigger-blank' )
|
||||
.attr( {
|
||||
'data-template-name-raw': 'Blank Form',
|
||||
'data-template': 'blank',
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Force focus on the form title field when switched to the Setup panel.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*
|
||||
* @param {Object|null} e Event object.
|
||||
* @param {string|null} view Current view.
|
||||
*/
|
||||
setupTitleFocus( e = null, view = null ) { // eslint-disable-line no-unused-vars
|
||||
view = view || wpf.getQueryString( 'view' );
|
||||
|
||||
if ( view !== 'setup' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clone form title to the Setup page.
|
||||
$( '#wpforms-setup-name' ).val( $( '#wpforms-panel-field-settings-form_title' ).val() );
|
||||
|
||||
el.$formName.trigger( 'focus' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Mark the current form template as selected.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
setSelectedTemplate() {
|
||||
if ( ! el.$panel.length || ! wpforms_builder.form_meta?.template ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $template = el.$builder
|
||||
.find( `.wpforms-template-select[data-template="${ wpforms_builder.form_meta.template }"]` )
|
||||
.closest( '.wpforms-template' );
|
||||
|
||||
if ( ! $template.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$template
|
||||
.addClass( 'selected' )
|
||||
.addClass( 'badge' );
|
||||
|
||||
// Remove existing badge.
|
||||
$template.find( '.wpforms-badge' ).remove();
|
||||
|
||||
// Remove edit and delete action buttons from current user template.
|
||||
if ( $template.hasClass( 'wpforms-user-template' ) ) {
|
||||
$template.find( '.wpforms-template-edit, .wpforms-template-remove' ).remove();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set category and/or subcategory active if its template was selected.
|
||||
*
|
||||
* @since 1.8.9
|
||||
*/
|
||||
setSelectedCategories() {
|
||||
if ( ! el.$panel.length || ! wpforms_builder.form_meta?.category ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $category = el.$categories.find( `li[data-category="${ wpforms_builder.form_meta.category }"]` );
|
||||
|
||||
if ( ! $category.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
el.$categories.find( 'li' ).removeClass( 'active opened' );
|
||||
$category.addClass( 'active opened' );
|
||||
|
||||
const $subcategory = el.$subcategories.find( `li[data-subcategory="${ wpforms_builder.form_meta.subcategory }"]` );
|
||||
|
||||
if ( ! $subcategory.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
el.$subcategories.find( 'li' ).removeClass( 'active' );
|
||||
$subcategory.addClass( 'active' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Filter templates by selected category and subcategory.
|
||||
*
|
||||
* @since 1.8.9
|
||||
*/
|
||||
filterTemplatesBySelectedCategory() {
|
||||
const $subCategory = el.$subcategories.find( 'li.active' );
|
||||
|
||||
// If subcategory is available, trigger its click it will update and category also.
|
||||
if ( $subCategory.length ) {
|
||||
$subCategory.trigger( 'click' );
|
||||
}
|
||||
|
||||
const $category = el.$categories.find( '> li.active' );
|
||||
|
||||
// In another case, click on the category.
|
||||
if (
|
||||
! $subCategory.length &&
|
||||
$category.length &&
|
||||
$category.data( 'category' ) !== 'all'
|
||||
) {
|
||||
$category.find( 'div' ).trigger( 'click' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Keep Setup title and settings title instances the same.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
*/
|
||||
syncTitle( e ) {
|
||||
if ( e.target.id === 'wpforms-setup-name' ) {
|
||||
$( '#wpforms-panel-field-settings-form_title' ).val( e.target.value );
|
||||
} else {
|
||||
$( '#wpforms-setup-name' ).val( e.target.value );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Search template.
|
||||
*
|
||||
* @since 1.6.8
|
||||
* @since 1.7.7 Deprecated.
|
||||
*
|
||||
* @deprecated Use `WPFormsFormTemplates.searchTemplate` instead.
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
*/
|
||||
searchTemplate( e ) {
|
||||
console.warn( 'WARNING! Function "WPForms.Admin.Builder.Setup.searchTemplate( e )" has been deprecated, please use the new "WPFormsFormTemplates.searchTemplate( e )" function instead!' );
|
||||
|
||||
WPFormsFormTemplates.searchTemplate( e );
|
||||
},
|
||||
|
||||
/**
|
||||
* Select category.
|
||||
*
|
||||
* @since 1.6.8
|
||||
* @since 1.7.7 Deprecated.
|
||||
*
|
||||
* @deprecated Use `WPFormsFormTemplates.selectCategory` instead.
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
*/
|
||||
selectCategory( e ) {
|
||||
console.warn( 'WARNING! Function "WPForms.Admin.Builder.Setup.selectCategory( e )" has been deprecated, please use the new "WPFormsFormTemplates.selectCategory( e )" function instead!' );
|
||||
|
||||
WPFormsFormTemplates.selectCategory( e );
|
||||
},
|
||||
|
||||
/**
|
||||
* Select template.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*
|
||||
* @param {Object} event Event object.
|
||||
*/
|
||||
selectTemplate( event ) {
|
||||
event.preventDefault();
|
||||
|
||||
const $button = $( this );
|
||||
|
||||
// Don't do anything for templates that trigger education modal OR addons-modal.
|
||||
if ( $button.hasClass( 'education-modal' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const template = $button.data( 'template' );
|
||||
|
||||
// User templates are applied differently for new forms.
|
||||
if ( ! vars.formID && template.match( /wpforms-user-template-(\d+)/ ) && $button.data( 'create-url' ) ) {
|
||||
window.location.href = $button.data( 'create-url' );
|
||||
return;
|
||||
}
|
||||
|
||||
el.$panel.find( '.wpforms-template' ).removeClass( 'active' );
|
||||
$button.closest( '.wpforms-template' ).addClass( 'active' );
|
||||
|
||||
// Save the original label.
|
||||
$button.data( 'labelOriginal', $button.html() );
|
||||
|
||||
// Display loading indicator.
|
||||
$button.html( vars.spinner + wpforms_builder.loading );
|
||||
|
||||
const formName = app.getFormName( $button );
|
||||
|
||||
app.applyTemplate( formName, template, $button );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get form name.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @param {jQuery} $button Pressed template button.
|
||||
*
|
||||
* @return {string} A new form name.
|
||||
*/
|
||||
getFormName( $button ) {
|
||||
const templateName = $button.data( 'template-name-raw' );
|
||||
const formName = el.$formName.val();
|
||||
|
||||
if ( ! formName ) {
|
||||
return templateName;
|
||||
}
|
||||
|
||||
return activeTemplateName === formName ? templateName : formName;
|
||||
},
|
||||
|
||||
/**
|
||||
* Apply template.
|
||||
*
|
||||
* The final part of the select template routine.
|
||||
*
|
||||
* @since 1.6.9
|
||||
*
|
||||
* @param {string} formName Name of the form.
|
||||
* @param {string} template Template slug.
|
||||
* @param {jQuery} $button Use a template button object.
|
||||
*/
|
||||
applyTemplate( formName, template, $button ) {
|
||||
el.$builder.trigger( 'wpformsTemplateSelect', template );
|
||||
|
||||
if ( vars.formID ) {
|
||||
// Existing form.
|
||||
app.selectTemplateExistingForm( formName, template, $button );
|
||||
} else {
|
||||
// Create a new form.
|
||||
WPFormsFormTemplates.selectTemplateProcess( formName, template, $button, app.selectTemplateProcessAjax );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Select Blank template.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
*/
|
||||
selectBlankTemplate( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
const $button = $( e.target ),
|
||||
formName = el.$formName.val() || wpforms_builder.blank_form,
|
||||
template = 'blank';
|
||||
|
||||
app.applyTemplate( formName, template, $button );
|
||||
},
|
||||
|
||||
/**
|
||||
* Select template. Existing form.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*
|
||||
* @param {string} formName Name of the form.
|
||||
* @param {string} template Template slug.
|
||||
* @param {jQuery} $button Use a template button object.
|
||||
*/
|
||||
selectTemplateExistingForm( formName, template, $button ) {
|
||||
$.confirm( {
|
||||
title: wpforms_builder.heads_up,
|
||||
content: wpforms_builder.template_confirm,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_builder.ok,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action() {
|
||||
WPFormsFormTemplates.selectTemplateProcess( formName, template, $button, app.selectTemplateProcessAjax );
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_builder.cancel,
|
||||
action() {
|
||||
WPFormsFormTemplates.selectTemplateCancel();
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Select template.
|
||||
*
|
||||
* @since 1.6.8
|
||||
* @since 1.8.2 Deprecated.
|
||||
*
|
||||
* @deprecated Use `WPFormsFormTemplates.selectTemplateProcess` instead.
|
||||
*
|
||||
* @param {string} formName Name of the form.
|
||||
* @param {string} template Template slug.
|
||||
* @param {jQuery} $button Use a template button object.
|
||||
*/
|
||||
selectTemplateProcess( formName, template, $button ) {
|
||||
console.warn( 'WARNING! Function "WPForms.Admin.Builder.Setup.selectTemplateProcess( formName, template, $button )" has been deprecated, please use the new "WPFormsFormTemplates.selectTemplateProcess( formName, template, $button, callback )" function instead!' );
|
||||
|
||||
WPFormsFormTemplates.selectTemplateProcess( formName, template, $button, app.selectTemplateProcessAjax );
|
||||
},
|
||||
|
||||
/**
|
||||
* Cancel button click routine.
|
||||
*
|
||||
* @since 1.6.8
|
||||
* @since 1.7.7 Deprecated.
|
||||
*
|
||||
* @deprecated Use `WPFormsFormTemplates.selectTemplateCancel` instead.
|
||||
*/
|
||||
selectTemplateCancel( ) {
|
||||
console.warn( 'WARNING! Function "WPForms.Admin.Builder.Setup.selectTemplateCancel" has been deprecated, please use the new "WPFormsFormTemplates.selectTemplateCancel" function instead!' );
|
||||
|
||||
WPFormsFormTemplates.selectTemplateCancel();
|
||||
},
|
||||
|
||||
/**
|
||||
* Select template. Create or update form AJAX call.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*
|
||||
* @param {string} formName Name of the form.
|
||||
* @param {string} template Template slug.
|
||||
*/
|
||||
selectTemplateProcessAjax( formName, template ) {
|
||||
WPFormsBuilder.showLoadingOverlay();
|
||||
|
||||
const data = {
|
||||
title: formName,
|
||||
action: vars.formID ? 'wpforms_update_form_template' : 'wpforms_new_form',
|
||||
template,
|
||||
form_id: vars.formID, // eslint-disable-line camelcase
|
||||
nonce: wpforms_builder.nonce,
|
||||
};
|
||||
|
||||
const category = $( '.wpforms-setup-templates-categories li.active' ).data( 'category' );
|
||||
const subcategory = $( '.wpforms-setup-templates-subcategories li.active' ).data( 'subcategory' );
|
||||
|
||||
if ( category ) {
|
||||
data.category = category;
|
||||
}
|
||||
|
||||
if ( subcategory ) {
|
||||
data.subcategory = subcategory;
|
||||
}
|
||||
|
||||
if ( category === 'all' ) {
|
||||
data.subcategory = 'all';
|
||||
}
|
||||
|
||||
$.post( wpforms_builder.ajax_url, data )
|
||||
.done( function( res ) {
|
||||
if ( res.success ) {
|
||||
// We have already warned the user that unsaved changes will be ignored.
|
||||
WPFormsBuilder.setCloseConfirmation( false );
|
||||
|
||||
window.location.href = wpf.getQueryString( 'force_desktop_view' )
|
||||
? wpf.updateQueryString( 'force_desktop_view', '1', res.data.redirect )
|
||||
: res.data.redirect;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
wpf.debug( res );
|
||||
|
||||
if ( res.data.error_type === 'invalid_template' ) {
|
||||
app.selectTemplateProcessInvalidTemplateError( res.data.message, formName );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
app.selectTemplateProcessError( res.data.message );
|
||||
} )
|
||||
.fail( function( xhr, textStatus ) {
|
||||
wpf.debug( xhr.responseText || textStatus || '' );
|
||||
app.selectTemplateProcessError( '' );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Select template AJAX call error modal for invalid template using.
|
||||
*
|
||||
* @since 1.7.5.3
|
||||
*
|
||||
* @param {string} errorMessage Error message.
|
||||
* @param {string} formName Name of the form.
|
||||
*/
|
||||
selectTemplateProcessInvalidTemplateError( errorMessage, formName ) {
|
||||
$.alert( {
|
||||
title: wpforms_builder.heads_up,
|
||||
content: errorMessage,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_builder.use_default_template,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action() {
|
||||
app.selectTemplateProcessAjax( formName, 'simple-contact-form-template' );
|
||||
WPFormsBuilder.hideLoadingOverlay();
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_builder.cancel,
|
||||
action() {
|
||||
WPFormsFormTemplates.selectTemplateCancel();
|
||||
WPFormsBuilder.hideLoadingOverlay();
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Select template AJAX call error modal.
|
||||
*
|
||||
* @since 1.6.8
|
||||
* @since 1.8.8 Replaced error message with error title.
|
||||
*
|
||||
* @param {string} errorTitle Error title.
|
||||
*/
|
||||
selectTemplateProcessError( errorTitle ) {
|
||||
$.alert( {
|
||||
title: errorTitle,
|
||||
content: wpforms_builder.error_select_template,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_builder.ok,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action() {
|
||||
WPFormsFormTemplates.selectTemplateCancel();
|
||||
WPFormsBuilder.hideLoadingOverlay();
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Open required addons alert.
|
||||
*
|
||||
* @since 1.6.8
|
||||
* @since 1.8.2 Deprecated.
|
||||
*
|
||||
* @deprecated Use `WPFormsFormTemplates.addonsModal` instead.
|
||||
*
|
||||
* @param {string} formName Name of the form.
|
||||
* @param {string} template Template slug.
|
||||
* @param {jQuery} $button Use a template button object.
|
||||
*/
|
||||
addonsModal( formName, template, $button ) {
|
||||
console.warn( 'WARNING! Function "WPForms.Admin.Builder.Setup.addonsModal( formName, template, $button )" has been deprecated, please use the new "WPFormsFormTemplates.addonsModal( formName, template, $button, callback )" function instead!' );
|
||||
|
||||
WPFormsFormTemplates.addonsModal( formName, template, $button, app.selectTemplateProcessAjax );
|
||||
},
|
||||
|
||||
/**
|
||||
* Install & Activate addons via AJAX.
|
||||
*
|
||||
* @since 1.6.8
|
||||
* @since 1.8.2 Deprecated.
|
||||
*
|
||||
* @deprecated Use `WPFormsFormTemplates.installActivateAddons` instead.
|
||||
*
|
||||
* @param {Array} addons Addons slugs.
|
||||
* @param {Object} previousModal Previous modal instance.
|
||||
* @param {string} formName Name of the form.
|
||||
* @param {string} template Template slug.
|
||||
*/
|
||||
installActivateAddons( addons, previousModal, formName, template ) {
|
||||
console.warn( 'WARNING! Function "WPForms.Admin.Builder.Setup.installActivateAddons( addons, previousModal, formName, template )" has been deprecated, please use the new "WPFormsFormTemplates.installActivateAddons( addons, previousModal, formName, template, callback )" function instead!' );
|
||||
|
||||
WPFormsFormTemplates.installActivateAddons( addons, previousModal, formName, template, app.selectTemplateProcessAjax );
|
||||
},
|
||||
|
||||
/**
|
||||
* Install & Activate addons error modal.
|
||||
*
|
||||
* @since 1.6.8
|
||||
* @since 1.8.2 Deprecated.
|
||||
*
|
||||
* @deprecated Use `WPFormsFormTemplates.installActivateAddonsError` instead.
|
||||
*
|
||||
* @param {string} formName Name of the form.
|
||||
* @param {string} template Template slug.
|
||||
*/
|
||||
installActivateAddonsError( formName, template ) {
|
||||
console.warn( 'WARNING! Function "WPForms.Admin.Builder.Setup.installActivateAddonsError( formName, template )" has been deprecated, please use the new "WPFormsFormTemplates.installActivateAddonsError( formName, template, callback )" function instead!' );
|
||||
|
||||
WPFormsFormTemplates.installActivateAddonsError( formName, template, app.selectTemplateProcessAjax );
|
||||
},
|
||||
|
||||
/**
|
||||
* Install & Activate single addon via AJAX.
|
||||
*
|
||||
* @since 1.6.8
|
||||
* @since 1.8.2 Deprecated.
|
||||
*
|
||||
* @deprecated Use `WPFormsFormTemplates.installActivateAddonAjax` instead.
|
||||
*
|
||||
* @param {string} addon Addon slug.
|
||||
*
|
||||
* @return {Promise} jQuery ajax call promise.
|
||||
*/
|
||||
installActivateAddonAjax( addon ) {
|
||||
console.warn( 'WARNING! Function "WPForms.Admin.Builder.Setup.installActivateAddonAjax( addon )" has been deprecated, please use the new "WPFormsFormTemplates.installActivateAddonAjax( addon )" function instead!' );
|
||||
|
||||
return WPFormsFormTemplates.installActivateAddonAjax( addon );
|
||||
},
|
||||
|
||||
/**
|
||||
* Initiate template processing for a new form.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*/
|
||||
applyTemplateOnRequest() {
|
||||
const urlParams = new URLSearchParams( window.location.search ),
|
||||
templateId = urlParams.get( 'template_id' );
|
||||
|
||||
if (
|
||||
urlParams.get( 'view' ) !== 'setup' ||
|
||||
urlParams.get( 'form_id' ) ||
|
||||
! templateId
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
el.$panel.find( '.wpforms-template .wpforms-btn[data-template="' + templateId + '"]' ).trigger( 'click' );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPForms.Admin.Builder.Setup.init();
|
||||
+1
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
+5
File diff suppressed because one or more lines are too long
@@ -0,0 +1,158 @@
|
||||
/* global wpforms_builder */
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
var WPForms = window.WPForms || {};
|
||||
WPForms.Admin = WPForms.Admin || {};
|
||||
WPForms.Admin.Builder = WPForms.Admin.Builder || {};
|
||||
|
||||
WPForms.Admin.Builder.Templates = WPForms.Admin.Builder.Templates || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Private functions and properties.
|
||||
*
|
||||
* @since 1.4.8
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const __private = {
|
||||
|
||||
/**
|
||||
* All templating functions for providers are stored here in a Map.
|
||||
* Key is a template name, value - Underscore.js templating function.
|
||||
*
|
||||
* @since 1.4.8
|
||||
*
|
||||
* @type {Map}
|
||||
*/
|
||||
previews: new Map(),
|
||||
|
||||
/**
|
||||
* Function to handle subfields for a given template's properties and extend
|
||||
* the fields list if applicable. The function processes fields for specific
|
||||
* types and formats, especially for "name" type fields, transforming them into
|
||||
* an extended format with additional subfields (Full, First, Middle, Last).
|
||||
*
|
||||
* If the `isSupportSubfields` property is not enabled in the provided template's
|
||||
* properties, the original `basePreview` function is executed without modification.
|
||||
*
|
||||
* @since 1.9.6
|
||||
*
|
||||
* @param {Function} basePreview The base preview function to execute the final output.
|
||||
*
|
||||
* @return {Function} A function that accepts `templateProps` and processes its fields.
|
||||
*/
|
||||
handleSubFields: ( basePreview ) => ( templateProps ) => {
|
||||
if ( ! templateProps?.isSupportSubfields ) {
|
||||
return basePreview( templateProps );
|
||||
}
|
||||
|
||||
const extendedFieldsList = {};
|
||||
let counter = 0;
|
||||
|
||||
_.each( templateProps.fields, function( field, key ) {
|
||||
if ( _.isEmpty( field ) || ! _.has( field, 'id' ) || ! _.has( field, 'type' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 'name' !== field.type || ! _.has( field, 'format' ) ) {
|
||||
extendedFieldsList[ counter++ ] = field;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
field.id = field.id.toString();
|
||||
|
||||
const fieldLabel = ! _.isUndefined( field.label ) && field.label.toString().trim() !== ''
|
||||
? field.label.toString().trim()
|
||||
: wpforms_builder.field + ' #' + key;
|
||||
|
||||
// Add data for Name field in "extended" format (Full, First, Middle and Last).
|
||||
_.each( wpforms_builder.name_field_formats, function( formatLabel, valueSlug ) {
|
||||
if ( -1 !== field.format.indexOf( valueSlug ) || valueSlug === 'full' ) {
|
||||
extendedFieldsList[ counter++ ] = {
|
||||
id: field.id + '.' + valueSlug,
|
||||
label: fieldLabel + ' (' + formatLabel + ')',
|
||||
format: field.format,
|
||||
};
|
||||
}
|
||||
} );
|
||||
} );
|
||||
|
||||
templateProps.fields = extendedFieldsList;
|
||||
|
||||
return basePreview( templateProps );
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.4.8
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine. DOM is not ready yet, use only to init something.
|
||||
*
|
||||
* @since 1.4.8
|
||||
*/
|
||||
init() {
|
||||
// Do that when DOM is ready.
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* DOM is fully loaded.
|
||||
*
|
||||
* @since 1.4.8
|
||||
*/
|
||||
ready() {
|
||||
$( '#wpforms-panel-providers' ).trigger( 'WPForms.Admin.Builder.Templates.ready' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Register and compile all templates.
|
||||
* All data is saved in a Map.
|
||||
*
|
||||
* @since 1.4.8
|
||||
*
|
||||
* @param {string[]} templates Array of template names.
|
||||
*/
|
||||
add( templates ) {
|
||||
templates.forEach( function( template ) {
|
||||
if ( typeof template === 'string' ) {
|
||||
__private.previews.set( template, wp.template( template ) );
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a templating function (to compile later with data).
|
||||
*
|
||||
* @since 1.4.8
|
||||
*
|
||||
* @param {string} template ID of a template to retrieve from a cache.
|
||||
*
|
||||
* @return {*} A callable that after compiling will always return a string.
|
||||
*/
|
||||
get( template ) {
|
||||
const preview = __private.previews.get( template );
|
||||
|
||||
if ( typeof preview !== 'undefined' ) {
|
||||
return __private.handleSubFields( preview );
|
||||
}
|
||||
|
||||
return function() {
|
||||
return '';
|
||||
};
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPForms.Admin.Builder.Templates.init();
|
||||
+1
@@ -0,0 +1 @@
|
||||
var WPForms=window.WPForms||{};WPForms.Admin=WPForms.Admin||{},WPForms.Admin.Builder=WPForms.Admin.Builder||{},WPForms.Admin.Builder.Templates=WPForms.Admin.Builder.Templates||(e=>{let i={previews:new Map,handleSubFields:i=>e=>{if(e?.isSupportSubfields){let t={},n=0;_.each(e.fields,function(d,e){if(!_.isEmpty(d)&&_.has(d,"id")&&_.has(d,"type"))if("name"===d.type&&_.has(d,"format")){d.id=d.id.toString();let r=_.isUndefined(d.label)||""===d.label.toString().trim()?wpforms_builder.field+" #"+e:d.label.toString().trim();_.each(wpforms_builder.name_field_formats,function(e,i){-1===d.format.indexOf(i)&&"full"!==i||(t[n++]={id:d.id+"."+i,label:r+" ("+e+")",format:d.format})})}else t[n++]=d}),e.fields=t}return i(e)}},r={init(){e(r.ready)},ready(){e("#wpforms-panel-providers").trigger("WPForms.Admin.Builder.Templates.ready")},add(e){e.forEach(function(e){"string"==typeof e&&i.previews.set(e,wp.template(e))})},get(e){e=i.previews.get(e);return void 0!==e?i.handleSubFields(e):function(){return""}}};return r})((document,window,jQuery)),WPForms.Admin.Builder.Templates.init();
|
||||
Executable
+109
@@ -0,0 +1,109 @@
|
||||
/* global wpforms_builder_themes_no_access */
|
||||
|
||||
/**
|
||||
* @param wpforms_builder_themes_no_access.strings.permission_modal.confirm
|
||||
* @param wpforms_builder_themes_no_access.strings.permission_modal.content
|
||||
* @param wpforms_builder_themes_no_access.strings.permission_modal.title
|
||||
*/
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
/**
|
||||
* WPForms Form builder themes - Non-admin version.
|
||||
*
|
||||
* @since 1.9.8
|
||||
*/
|
||||
var WPForms = window.WPForms || {}; // eslint-disable-line no-var
|
||||
|
||||
WPForms.Admin = WPForms.Admin || {};
|
||||
WPForms.Admin.Builder = WPForms.Admin.Builder || {};
|
||||
|
||||
WPForms.Admin.Builder.ThemesNoAccess = WPForms.Admin.Builder.ThemesNoAccess || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.9.8
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const el = {};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.9.8
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.9.8
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.9.8
|
||||
*/
|
||||
ready() {
|
||||
app.setup();
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup. Prepare some variables.
|
||||
*
|
||||
* @since 1.9.8
|
||||
*/
|
||||
setup() {
|
||||
// Cache DOM elements.
|
||||
el.$builder = $( '#wpforms-builder' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup events.
|
||||
*
|
||||
* @since 1.9.8
|
||||
*/
|
||||
events() {
|
||||
el.$builder.on( 'wpformsPanelSectionSwitch', app.handlePanelSectionSwitch );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle panel section switch and show permission modal.
|
||||
*
|
||||
* @since 1.9.8
|
||||
*
|
||||
* @param {Object} _event The event object.
|
||||
* @param {string} section The section that was switched to.
|
||||
*/
|
||||
handlePanelSectionSwitch( _event, section ) {
|
||||
if ( section === 'themes' ) {
|
||||
$.alert( {
|
||||
title: wpforms_builder_themes_no_access.strings.permission_modal.title,
|
||||
content: wpforms_builder_themes_no_access.strings.permission_modal.content,
|
||||
icon: 'fa fa-exclamation-triangle',
|
||||
type: 'red',
|
||||
theme: 'modern',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_builder_themes_no_access.strings.permission_modal.confirm,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
_event.preventDefault();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Return the public-facing methods.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPForms.Admin.Builder.ThemesNoAccess.init();
|
||||
Vendored
Executable
+1
@@ -0,0 +1 @@
|
||||
var WPForms=window.WPForms||{};WPForms.Admin=WPForms.Admin||{},WPForms.Admin.Builder=WPForms.Admin.Builder||{},WPForms.Admin.Builder.ThemesNoAccess=WPForms.Admin.Builder.ThemesNoAccess||(n=>{let e={},s={init(){n(s.ready)},ready(){s.setup(),s.events()},setup(){e.$builder=n("#wpforms-builder")},events(){e.$builder.on("wpformsPanelSectionSwitch",s.handlePanelSectionSwitch)},handlePanelSectionSwitch(e,s){"themes"===s&&(n.alert({title:wpforms_builder_themes_no_access.strings.permission_modal.title,content:wpforms_builder_themes_no_access.strings.permission_modal.content,icon:"fa fa-exclamation-triangle",type:"red",theme:"modern",buttons:{confirm:{text:wpforms_builder_themes_no_access.strings.permission_modal.confirm,btnClass:"btn-confirm",keys:["enter"]}}}),e.preventDefault())}};return s})((document,window,jQuery)),WPForms.Admin.Builder.ThemesNoAccess.init();
|
||||
+264
@@ -0,0 +1,264 @@
|
||||
/* global wpforms_builder_themes, wpf, WPFormsUtils */
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
/**
|
||||
* WPForms Form builder themes.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
var WPForms = window.WPForms || {}; // eslint-disable-line no-var
|
||||
|
||||
WPForms.Admin = WPForms.Admin || {};
|
||||
WPForms.Admin.Builder = WPForms.Admin.Builder || {};
|
||||
|
||||
WPForms.Admin.Builder.Themes = WPForms.Admin.Builder.Themes || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const el = {};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
ready() {
|
||||
app.setup();
|
||||
app.loadModules();
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup. Prepare some variables.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
setup() {
|
||||
// Cache DOM elements.
|
||||
el.$builder = $( '#wpforms-builder' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Centralized reactive store for theme style settings in the Form Builder.
|
||||
*
|
||||
* Provides a simple pub/sub mechanism to track and respond to setting changes.
|
||||
* Automatically initializes its state from all inputs/selects matching `name="settings[themes][...]"`.
|
||||
*
|
||||
* Usage examples:
|
||||
*
|
||||
* // Subscribe to a specific setting change.
|
||||
* app.store.subscribe('buttonTextColor', (value) => {
|
||||
* console.log('Button text color changed to:', value);
|
||||
* } );
|
||||
*
|
||||
* // Subscribe to all setting changes.
|
||||
* app.store.subscribeAll(( value, key) => {
|
||||
* console.log( Setting ${ key } changed to:`, value);
|
||||
* });
|
||||
*
|
||||
* // Get current value.
|
||||
* const padding = app.store.get('containerPadding');
|
||||
*
|
||||
* // Manually update a setting (will trigger listeners).
|
||||
* // Use the 3rd argument as 'true' to set in a 'silent' mode when state and input will update,
|
||||
* // but no listeners will be run.
|
||||
* app.store.set('fieldSize', 'medium');
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @type {Object}
|
||||
* @property {Function} get Get current value of a setting by key.
|
||||
* @property {Function} set Set value of a setting by key and notify listeners.
|
||||
* @property {Function} subscribe Subscribe to a specific setting change: (key, callback) => void
|
||||
* @property {Function} subscribeAll Subscribe to all setting changes: (callback) => void
|
||||
* @property {Function} initFromDOM Initialize the store from DOM inputs/selects.
|
||||
* @property {Object} state Raw internal state object (mostly for debugging).
|
||||
*/
|
||||
store: ( () => {
|
||||
const state = {};
|
||||
const keyListeners = new Map();
|
||||
const inputElements = new Map();
|
||||
const globalListeners = [];
|
||||
const debouncedSetters = {};
|
||||
const DEBOUNCE_DELAY = 50;
|
||||
|
||||
// Settings getter.
|
||||
const get = ( key ) => state[ key ];
|
||||
|
||||
// Settings setter.
|
||||
const set = ( key, value, silent = false ) => {
|
||||
if ( state[ key ] === value ) {
|
||||
return;
|
||||
}
|
||||
|
||||
state[ key ] = value;
|
||||
|
||||
const $input = inputElements.get( key );
|
||||
|
||||
if ( $input && $input.val() !== value ) {
|
||||
$input.val( value );
|
||||
if ( ! silent ) {
|
||||
$input.trigger( 'input' );
|
||||
}
|
||||
}
|
||||
|
||||
if ( silent ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( keyListeners.has( key ) ) {
|
||||
$.each( keyListeners.get( key ), ( _, cb ) => cb( value, key ) );
|
||||
}
|
||||
$.each( globalListeners, ( _, cb ) => cb( value, key ) );
|
||||
};
|
||||
|
||||
// Get bounced Setter.
|
||||
const getDebouncedSetter = ( key ) => {
|
||||
if ( ! debouncedSetters[ key ] ) {
|
||||
debouncedSetters[ key ] = _.debounce( ( value ) => set( key, value ), DEBOUNCE_DELAY );
|
||||
}
|
||||
return debouncedSetters[ key ];
|
||||
};
|
||||
|
||||
// Allow subscribing to specific setting change.
|
||||
const subscribe = ( key, callback ) => {
|
||||
if ( ! keyListeners.has( key ) ) {
|
||||
keyListeners.set( key, [] );
|
||||
}
|
||||
keyListeners.get( key ).push( callback );
|
||||
};
|
||||
|
||||
// Allow listening all settings change.
|
||||
const subscribeAll = ( callback ) => {
|
||||
globalListeners.push( callback );
|
||||
};
|
||||
|
||||
// Initialize from DOM (should be called once during app init).
|
||||
const initFromDOM = () => {
|
||||
$( '[name^="settings[themes]"]' ).each( function() {
|
||||
const $input = $( this );
|
||||
const nameMatch = $input.attr( 'name' ).match( /\[themes]\[(.*?)]/ );
|
||||
if ( ! nameMatch ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const key = nameMatch[ 1 ];
|
||||
state[ key ] = $input.val();
|
||||
inputElements.set( key, $input );
|
||||
|
||||
const tag = $input.prop( 'tagName' ).toLowerCase();
|
||||
const type = ( $input.attr( 'type' ) || '' ).toLowerCase();
|
||||
|
||||
const isDebouncedInput = (
|
||||
( tag === 'input' && ( type === 'text' || type === 'number' || type === 'hidden' ) ) ||
|
||||
tag === 'textarea'
|
||||
);
|
||||
|
||||
$input.on( isDebouncedInput ? 'input' : 'change', function() {
|
||||
const value = $( this ).val();
|
||||
if ( isDebouncedInput ) {
|
||||
getDebouncedSetter( key )( value );
|
||||
} else {
|
||||
set( key, value );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
};
|
||||
|
||||
return {
|
||||
get,
|
||||
set,
|
||||
subscribe,
|
||||
subscribeAll,
|
||||
initFromDOM,
|
||||
inputElements,
|
||||
state,
|
||||
};
|
||||
}
|
||||
)(),
|
||||
|
||||
/**
|
||||
* Get setting.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {null|string} key Settings key.
|
||||
*
|
||||
* @return {Object} Setting value.
|
||||
*/
|
||||
getSettings( key = null ) {
|
||||
if ( key ) {
|
||||
return app.store.get( key );
|
||||
}
|
||||
return app.store.state;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get controls.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {null|string} key Settings key.
|
||||
*
|
||||
* @return {Object} Control
|
||||
*/
|
||||
getControls( key = null ) {
|
||||
if ( key ) {
|
||||
return app.store.inputElements.get( key );
|
||||
}
|
||||
return app.store.inputElements;
|
||||
},
|
||||
|
||||
/**
|
||||
* Load modules.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
loadModules() {
|
||||
const modules = wpforms_builder_themes.modules || [];
|
||||
|
||||
// Import all modules dynamically.
|
||||
Promise.all( modules.map( ( module ) => import( module.path ) ) )
|
||||
.then( ( importedModules ) => {
|
||||
importedModules.forEach( ( module, index ) => {
|
||||
const moduleName = modules[ index ].name;
|
||||
app[ moduleName ] = module.default( document, window, $ );
|
||||
|
||||
// Initialize module on `wpformsBuilderThemesLoaded` event.
|
||||
el.$builder.on( `wpformsBuilderThemesLoaded`, app[ moduleName ].init );
|
||||
} );
|
||||
|
||||
// Trigger `wpformsBuilderThemesLoaded` event.
|
||||
WPFormsUtils.triggerEvent( el.$builder, 'wpformsBuilderThemesLoaded', [ importedModules ] );
|
||||
} )
|
||||
.catch( ( error ) => {
|
||||
wpf.debug( 'Error importing modules:', error );
|
||||
} );
|
||||
},
|
||||
};
|
||||
|
||||
// Return the public-facing methods.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPForms.Admin.Builder.Themes.init();
|
||||
Vendored
Executable
+1
@@ -0,0 +1 @@
|
||||
var WPForms=window.WPForms||{};WPForms.Admin=WPForms.Admin||{},WPForms.Admin.Builder=WPForms.Admin.Builder||{},WPForms.Admin.Builder.Themes=WPForms.Admin.Builder.Themes||((s,i,d)=>{let n={},o={init(){d(o.ready)},ready(){o.setup(),o.loadModules()},setup(){n.$builder=d("#wpforms-builder")},store:(()=>{let n={},i=new Map,o=new Map,m=[],a={},l=50;let u=(r,s,e=!1)=>{var t;n[r]===s||(n[r]=s,(t=o.get(r))&&t.val()!==s&&(t.val(s),e||t.trigger("input")),e)||(i.has(r)&&d.each(i.get(r),(e,t)=>t(s,r)),d.each(m,(e,t)=>t(s,r)))};return{get:e=>n[e],set:u,subscribe:(e,t)=>{i.has(e)||i.set(e,[]),i.get(e).push(t)},subscribeAll:e=>{m.push(e)},initFromDOM:()=>{d('[name^="settings[themes]"]').each(function(){var e=d(this),t=e.attr("name").match(/\[themes]\[(.*?)]/);if(t){let r=t[1];n[r]=e.val(),o.set(r,e);var t=e.prop("tagName").toLowerCase(),i=(e.attr("type")||"").toLowerCase();let s="input"===t&&("text"===i||"number"===i||"hidden"===i)||"textarea"===t;e.on(s?"input":"change",function(){var t,e=d(this).val();s?(t=r,a[t]||(a[t]=_.debounce(e=>u(t,e),l)),a[t])(e):u(r,e)})}})},inputElements:o,state:n}})(),getSettings(e=null){return e?o.store.get(e):o.store.state},getControls(e=null){return e?o.store.inputElements.get(e):o.store.inputElements},loadModules(){let r=wpforms_builder_themes.modules||[];Promise.all(r.map(e=>import(e.path))).then(e=>{e.forEach((e,t)=>{t=r[t].name;o[t]=e.default(s,i,d),n.$builder.on("wpformsBuilderThemesLoaded",o[t].init)}),WPFormsUtils.triggerEvent(n.$builder,"wpformsBuilderThemesLoaded",[e])}).catch(e=>{wpf.debug("Error importing modules:",e)})}};return o})(document,window,jQuery),WPForms.Admin.Builder.Themes.init();
|
||||
Executable
+221
@@ -0,0 +1,221 @@
|
||||
/* global wpforms_builder_themes */
|
||||
|
||||
/**
|
||||
* WPForms Form Builder Themes: Advanced settings module.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {Object} document Document object.
|
||||
* @param {Object} window Window object.
|
||||
* @param {jQuery} $ jQuery object.
|
||||
*
|
||||
* @return {Object} Public functions and properties.
|
||||
*/
|
||||
export default function( document, window, $ ) { // eslint-disable-line max-lines-per-function
|
||||
const WPForms = window.WPForms || {};
|
||||
const WPFormsBuilderThemes = WPForms.Admin.Builder.Themes || {};
|
||||
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const el = {};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
init() {
|
||||
app.setup();
|
||||
app.events();
|
||||
|
||||
// Subscribe to all settings change.
|
||||
WPFormsBuilderThemes.store.subscribeAll( ( value, key ) => {
|
||||
app.updateCopyPasteContent( value, key );
|
||||
} );
|
||||
|
||||
app.disableSpellCheck();
|
||||
app.updateCopyPasteContent();
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
setup() {
|
||||
el.$builder = $( '#wpforms-builder' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
events() {
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the list of the settings key allowed to show in the Copy/paste field.
|
||||
*
|
||||
* @since 1.9.7
|
||||
* @return {Array} List of allowed settings.
|
||||
*/
|
||||
getAllowedKeys() {
|
||||
const allowedKeys = [ 'themeName', 'isCustomTheme', 'wpformsTheme', 'customCss' ];
|
||||
const styleSettings = WPFormsBuilderThemes.common.getStyleAttributesKeys();
|
||||
|
||||
return allowedKeys.concat( styleSettings );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the content of the "Copy/Paste" field.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} value Setting value
|
||||
* @param {string} key Setting key.
|
||||
*/
|
||||
updateCopyPasteContent( value = '', key = '' ) {
|
||||
if ( key === 'copyPasteJsonValue' ) {
|
||||
app.pasteSettings( value );
|
||||
return;
|
||||
}
|
||||
|
||||
const content = {};
|
||||
const allowedKeys = app.getAllowedKeys();
|
||||
const settings = WPFormsBuilderThemes.getSettings();
|
||||
|
||||
allowedKeys.forEach( ( settingKey ) => {
|
||||
content[ settingKey ] = settings[ settingKey ];
|
||||
} );
|
||||
|
||||
// Update field content in a 'silent' mode.
|
||||
WPFormsBuilderThemes.store.set( 'copyPasteJsonValue', JSON.stringify( content ), true );
|
||||
},
|
||||
|
||||
/**
|
||||
* Paste settings handler.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} value New attribute value.
|
||||
*/
|
||||
pasteSettings( value ) {
|
||||
value = value.trim();
|
||||
|
||||
const pasteAttributes = app.parseValidateJson( value );
|
||||
|
||||
// Show the error modal if JSON is broken.
|
||||
if ( ! pasteAttributes ) {
|
||||
if ( value ) {
|
||||
app.showJsonErrorModal();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const themeSlug = pasteAttributes?.wpformsTheme ?? pasteAttributes?.theme;
|
||||
const currentThemeSlug = WPFormsBuilderThemes.store.get( 'wpformsTheme' );
|
||||
const theme = WPFormsBuilderThemes.themes.getTheme( themeSlug );
|
||||
|
||||
// If the theme already exists - set it.
|
||||
if ( theme && themeSlug !== currentThemeSlug ) {
|
||||
WPFormsBuilderThemes.themes.setFormTheme( themeSlug );
|
||||
WPFormsBuilderThemes.themes.updateThemesList();
|
||||
return;
|
||||
}
|
||||
|
||||
// For not existed theme - parse and set settings.
|
||||
const allowedKeys = app.getAllowedKeys();
|
||||
|
||||
allowedKeys.forEach( ( settingKey ) => {
|
||||
if ( pasteAttributes[ settingKey ] !== undefined ) {
|
||||
let settingValue = pasteAttributes[ settingKey ];
|
||||
|
||||
settingValue = typeof settingValue === 'string'
|
||||
? settingValue.replace( /px$/, '' )
|
||||
: settingValue;
|
||||
|
||||
WPFormsBuilderThemes.store.set( settingKey, settingValue );
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Parse and validate JSON string.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} value JSON string.
|
||||
*
|
||||
* @return {boolean|object} Parsed JSON object OR false on error.
|
||||
*/
|
||||
parseValidateJson( value ) {
|
||||
if ( typeof value !== 'string' ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let atts;
|
||||
|
||||
try {
|
||||
atts = JSON.parse( value.trim() );
|
||||
} catch ( error ) {
|
||||
atts = false;
|
||||
}
|
||||
|
||||
return atts;
|
||||
},
|
||||
|
||||
/**
|
||||
* Show the error when pasted JSON is broken.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
showJsonErrorModal() {
|
||||
$.alert( {
|
||||
title: wpforms_builder_themes.strings.uhoh,
|
||||
content: wpforms_builder_themes.strings.copy_paste_error,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'red',
|
||||
buttons: {
|
||||
cancel: {
|
||||
text: wpforms_builder_themes.strings.close,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Disable spellcheck for the textarea settings fields.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
disableSpellCheck() {
|
||||
const customCssControl = WPFormsBuilderThemes.getControls( 'customCss' );
|
||||
const copyPasteControl = WPFormsBuilderThemes.getControls( 'copyPasteJsonValue' );
|
||||
|
||||
if ( ! customCssControl || ! copyPasteControl ) {
|
||||
return;
|
||||
}
|
||||
|
||||
copyPasteControl.attr( 'spellcheck', 'false' );
|
||||
customCssControl.attr( 'spellcheck', 'false' );
|
||||
},
|
||||
};
|
||||
|
||||
return app;
|
||||
}
|
||||
Vendored
Executable
+1
@@ -0,0 +1 @@
|
||||
export default function(e,t,s){let o=(t.WPForms||{}).Admin.Builder.Themes||{},r={},l={init(){l.setup(),l.events(),o.store.subscribeAll((e,t)=>{l.updateCopyPasteContent(e,t)}),l.disableSpellCheck(),l.updateCopyPasteContent()},setup(){r.$builder=s("#wpforms-builder")},events(){},getAllowedKeys(){var e=o.common.getStyleAttributesKeys();return["themeName","isCustomTheme","wpformsTheme","customCss"].concat(e)},updateCopyPasteContent(e="",r=""){if("copyPasteJsonValue"===r)l.pasteSettings(e);else{let t={};r=l.getAllowedKeys();let s=o.getSettings();r.forEach(e=>{t[e]=s[e]}),o.store.set("copyPasteJsonValue",JSON.stringify(t),!0)}},pasteSettings(e){e=e.trim();let s=l.parseValidateJson(e);var t,r;s?(t=s?.wpformsTheme??s?.theme,r=o.store.get("wpformsTheme"),o.themes.getTheme(t)&&t!==r?(o.themes.setFormTheme(t),o.themes.updateThemesList()):l.getAllowedKeys().forEach(t=>{if(void 0!==s[t]){let e=s[t];e="string"==typeof e?e.replace(/px$/,""):e,o.store.set(t,e)}})):e&&l.showJsonErrorModal()},parseValidateJson(e){if("string"!=typeof e)return!1;let t;try{t=JSON.parse(e.trim())}catch(e){t=!1}return t},showJsonErrorModal(){s.alert({title:wpforms_builder_themes.strings.uhoh,content:wpforms_builder_themes.strings.copy_paste_error,icon:"fa fa-exclamation-circle",type:"red",buttons:{cancel:{text:wpforms_builder_themes.strings.close,btnClass:"btn-confirm",keys:["enter"]}}})},disableSpellCheck(){var e=o.getControls("customCss"),t=o.getControls("copyPasteJsonValue");e&&t&&(t.attr("spellcheck","false"),e.attr("spellcheck","false"))}};return l}
|
||||
+367
@@ -0,0 +1,367 @@
|
||||
/**
|
||||
* WPForms Form Builder Themes: Background module.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {Object} document Document object.
|
||||
* @param {Object} window Window object.
|
||||
* @param {jQuery} $ jQuery object.
|
||||
*
|
||||
* @return {Object} Public functions and properties.
|
||||
*/
|
||||
export default function( document, window, $ ) {// eslint-disable-line max-lines-per-function
|
||||
const WPForms = window.WPForms || {};
|
||||
const WPFormsBuilderThemes = WPForms.Admin.Builder.Themes || {};
|
||||
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const el = {};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
init() {
|
||||
app.setup();
|
||||
app.events();
|
||||
|
||||
WPFormsBuilderThemes.store.subscribe( 'backgroundUrl', ( value ) => {
|
||||
app.setImagePreview( value );
|
||||
app.maybeShowChooseButton();
|
||||
} );
|
||||
|
||||
WPFormsBuilderThemes.store.subscribe( 'backgroundImage', ( value ) => {
|
||||
app.maybeShowImageSelector( value );
|
||||
app.maybeShowChooseButton();
|
||||
} );
|
||||
|
||||
WPFormsBuilderThemes.store.subscribe( 'backgroundSizeMode', ( value ) => {
|
||||
app.handleSizeFromDimensions( value );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
setup() {
|
||||
el.$builder = $( '#wpforms-builder' );
|
||||
el.$preview = $( '#wpforms-builder-themes-preview' );
|
||||
el.$imageSelector = $( '.wpforms-builder-themes-background-selector' );
|
||||
el.$imagePreview = el.$imageSelector.find( '.wpforms-builder-themes-bg-image-preview' );
|
||||
el.$chooseButton = el.$imageSelector.find( '.wpforms-builder-themes-bg-image-choose' );
|
||||
el.$removeButton = el.$imageSelector.find( '.wpforms-builder-themes-bg-image-remove' );
|
||||
|
||||
app.initImageSelector();
|
||||
},
|
||||
|
||||
/**
|
||||
* Events.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
events() {
|
||||
el.$builder
|
||||
.on( 'click', '.wpforms-builder-themes-bg-image-remove', app.removeImage )
|
||||
.on( 'click', '.wpforms-builder-themes-bg-image-choose, .wpforms-builder-themes-bg-image-preview', app.chooseImage );
|
||||
},
|
||||
|
||||
/**
|
||||
* Init the Image Selector control.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
initImageSelector() {
|
||||
const settings = WPFormsBuilderThemes.getSettings();
|
||||
|
||||
el.$imageSelector.removeClass( 'wpforms-hidden' );
|
||||
|
||||
app.setImagePreview( settings.backgroundUrl );
|
||||
app.maybeShowChooseButton();
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle image selector control state.
|
||||
*
|
||||
* @since 1.9.7
|
||||
* @param {string} value `backgroundImage` setting value.
|
||||
*/
|
||||
maybeShowImageSelector( value ) {
|
||||
if ( value === 'none' ) {
|
||||
el.$imageSelector.addClass( 'wpforms-hidden' );
|
||||
} else {
|
||||
el.$imageSelector.removeClass( 'wpforms-hidden' );
|
||||
|
||||
const backgroundUrl = WPFormsBuilderThemes.store.get( 'backgroundUrl' );
|
||||
|
||||
// Here we need to clean the url value and set a new one.
|
||||
// Otherwise, the picture preview won't be updated.
|
||||
WPFormsBuilderThemes.store.set( 'backgroundUrl', 'url()' );
|
||||
WPFormsBuilderThemes.store.set( 'backgroundUrl', backgroundUrl );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove an image button handler.
|
||||
*
|
||||
* @param {Object} e Event object
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
removeImage( e ) {
|
||||
e.preventDefault();
|
||||
WPFormsBuilderThemes.store.set( 'backgroundUrl', 'url()' );
|
||||
el.$chooseButton.removeClass( 'wpforms-hidden' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Choose an image button handler.
|
||||
*
|
||||
* @param {Object} e Event object
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
chooseImage( e ) {
|
||||
e.preventDefault();
|
||||
const settings = WPFormsBuilderThemes.getSettings();
|
||||
|
||||
if ( settings.backgroundImage === 'library' ) {
|
||||
app.openMediaLibrary();
|
||||
} else {
|
||||
WPFormsBuilderThemes.stockPhotos.openModal( 'bg-styles' );
|
||||
}
|
||||
|
||||
app.maybeShowChooseButton();
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the image preview.
|
||||
*
|
||||
* @param {null|string} value Image preview url value.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
setImagePreview( value = null ) {
|
||||
const isHidden = ! value || value === 'url()';
|
||||
const imageValue = isHidden ? 'url()' : `url(${ value })`;
|
||||
|
||||
el.$imagePreview.css( 'background-image', imageValue );
|
||||
el.$imagePreview.toggleClass( 'wpforms-hidden', isHidden );
|
||||
el.$removeButton.toggleClass( 'wpforms-hidden', isHidden );
|
||||
},
|
||||
|
||||
/**
|
||||
* Conditionally show or hide the `Choose Image` button.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
maybeShowChooseButton() {
|
||||
const settings = WPFormsBuilderThemes.getSettings();
|
||||
|
||||
if ( settings.backgroundImage !== 'none' && settings.backgroundUrl === 'url()' ) {
|
||||
el.$chooseButton.removeClass( 'wpforms-hidden' );
|
||||
} else {
|
||||
el.$chooseButton.addClass( 'wpforms-hidden' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Open media library modal and handle image selection.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
openMediaLibrary() {
|
||||
const frame = wp.media( {
|
||||
multiple: false,
|
||||
library: {
|
||||
type: 'image',
|
||||
},
|
||||
} );
|
||||
|
||||
frame.on( 'select', () => {
|
||||
const attachment = frame.state().get( 'selection' ).first().toJSON();
|
||||
|
||||
if ( attachment.url ) {
|
||||
WPFormsBuilderThemes.store.set( 'backgroundUrl', attachment.url );
|
||||
}
|
||||
} );
|
||||
|
||||
frame.open();
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle the real size from image dimensions.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} value Value.
|
||||
*/
|
||||
handleSizeFromDimensions( value ) {
|
||||
const settings = WPFormsBuilderThemes.getSettings();
|
||||
const $container = el.$preview.find( '.wpforms-container' )[ 0 ];
|
||||
const backgroundWidth = WPFormsBuilderThemes.common.prepareComplexAttrValues( settings.backgroundWidth, 'backgroundWidth' );
|
||||
const backgroundHeight = WPFormsBuilderThemes.common.prepareComplexAttrValues( settings.backgroundHeight, 'backgroundHeight' );
|
||||
const $backgroundSizeControl = WPFormsBuilderThemes.getControls( 'backgroundSize' );
|
||||
|
||||
if ( value === 'cover' ) {
|
||||
app.setContainerBackgroundWidth( $container, backgroundWidth );
|
||||
app.setContainerBackgroundHeight( $container, backgroundHeight );
|
||||
|
||||
$container.style.setProperty( `--wpforms-background-size`, 'cover' );
|
||||
$backgroundSizeControl.val( 'cover' );
|
||||
} else {
|
||||
$container.style.setProperty( `--wpforms-background-size`, backgroundWidth + ' ' + backgroundHeight );
|
||||
$backgroundSizeControl.val( backgroundWidth + ' ' + backgroundHeight );
|
||||
}
|
||||
|
||||
$backgroundSizeControl.trigger( 'input' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle real size from height.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {HTMLElement} container Form preview container
|
||||
* @param {string} value Value.
|
||||
* @param {Object} atts Form style settings.
|
||||
*/
|
||||
handleSizeFromHeight( container, value, atts ) {
|
||||
const backgroundWidth = WPFormsBuilderThemes.common.prepareComplexAttrValues( atts.backgroundWidth, 'backgroundWidth' );
|
||||
const $backgroundSizeControl = WPFormsBuilderThemes.getControls( 'backgroundSize' );
|
||||
|
||||
app.setContainerBackgroundHeight( container, value );
|
||||
|
||||
if ( atts.backgroundSizeMode !== 'cover' ) {
|
||||
$backgroundSizeControl.val( backgroundWidth + ' ' + value );
|
||||
container.style.setProperty( `--wpforms-background-size`, backgroundWidth + ' ' + value );
|
||||
$backgroundSizeControl.trigger( 'input' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle real size from width.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {HTMLElement} container Form preview container
|
||||
* @param {string} value Value.
|
||||
* @param {Object} atts Form style settings.
|
||||
*/
|
||||
handleSizeFromWidth( container, value, atts ) {
|
||||
const backgroundWidth = WPFormsBuilderThemes.common.prepareComplexAttrValues( atts.backgroundWidth, 'backgroundWidth' );
|
||||
const backgroundHeight = WPFormsBuilderThemes.common.prepareComplexAttrValues( atts.backgroundHeight, 'backgroundHeight' );
|
||||
const $backgroundSizeControl = WPFormsBuilderThemes.getControls( 'backgroundSize' );
|
||||
|
||||
app.setContainerBackgroundWidth( container, backgroundWidth );
|
||||
|
||||
if ( atts.backgroundSizeMode !== 'cover' ) {
|
||||
$backgroundSizeControl.val( value + ' ' + backgroundHeight );
|
||||
container.style.setProperty( `--wpforms-background-size`, value + ' ' + backgroundHeight );
|
||||
$backgroundSizeControl.trigger( 'input' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the container background color.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {HTMLElement} container Container element.
|
||||
* @param {string} value Value.
|
||||
*/
|
||||
setBackgroundColor( container, value ) {
|
||||
container.style.setProperty( `--wpforms-background-color`, value );
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the container background url.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {HTMLElement} container Container element.
|
||||
* @param {string} value Value.
|
||||
*/
|
||||
setBackgroundUrl( container, value ) {
|
||||
container.style.setProperty( `--wpforms-background-url`, value );
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the container background height.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {HTMLElement} container Container element.
|
||||
* @param {string} value Value.
|
||||
*/
|
||||
setContainerBackgroundHeight( container, value ) {
|
||||
container.style.setProperty( `--wpforms-background-height`, value );
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the container background image.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {HTMLElement} container Container element.
|
||||
* @param {string} value Value.
|
||||
*/
|
||||
setContainerBackgroundImage( container, value ) {
|
||||
if ( value === 'none' ) {
|
||||
container.style.setProperty( `--wpforms-background-url`, 'url()' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the container background position.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {HTMLElement} container Container element.
|
||||
* @param {string} value Value.
|
||||
*/
|
||||
setContainerBackgroundPosition( container, value ) {
|
||||
container.style.setProperty( `--wpforms-background-position`, value );
|
||||
},
|
||||
|
||||
/**
|
||||
* Set container background repeat.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {HTMLElement} container Container element.
|
||||
* @param {string} value Value.
|
||||
*/
|
||||
setContainerBackgroundRepeat( container, value ) {
|
||||
container.style.setProperty( `--wpforms-background-repeat`, value );
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the container background width.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {HTMLElement} container Container element.
|
||||
* @param {string} value Value.
|
||||
*/
|
||||
setContainerBackgroundWidth( container, value ) {
|
||||
container.style.setProperty( `--wpforms-background-width`, value );
|
||||
},
|
||||
};
|
||||
|
||||
return app;
|
||||
}
|
||||
Vendored
Executable
+1
@@ -0,0 +1 @@
|
||||
export default function(e,r,o){let n=(r.WPForms||{}).Admin.Builder.Themes||{},a={},i={init(){i.setup(),i.events(),n.store.subscribe("backgroundUrl",e=>{i.setImagePreview(e),i.maybeShowChooseButton()}),n.store.subscribe("backgroundImage",e=>{i.maybeShowImageSelector(e),i.maybeShowChooseButton()}),n.store.subscribe("backgroundSizeMode",e=>{i.handleSizeFromDimensions(e)})},setup(){a.$builder=o("#wpforms-builder"),a.$preview=o("#wpforms-builder-themes-preview"),a.$imageSelector=o(".wpforms-builder-themes-background-selector"),a.$imagePreview=a.$imageSelector.find(".wpforms-builder-themes-bg-image-preview"),a.$chooseButton=a.$imageSelector.find(".wpforms-builder-themes-bg-image-choose"),a.$removeButton=a.$imageSelector.find(".wpforms-builder-themes-bg-image-remove"),i.initImageSelector()},events(){a.$builder.on("click",".wpforms-builder-themes-bg-image-remove",i.removeImage).on("click",".wpforms-builder-themes-bg-image-choose, .wpforms-builder-themes-bg-image-preview",i.chooseImage)},initImageSelector(){var e=n.getSettings();a.$imageSelector.removeClass("wpforms-hidden"),i.setImagePreview(e.backgroundUrl),i.maybeShowChooseButton()},maybeShowImageSelector(e){"none"===e?a.$imageSelector.addClass("wpforms-hidden"):(a.$imageSelector.removeClass("wpforms-hidden"),e=n.store.get("backgroundUrl"),n.store.set("backgroundUrl","url()"),n.store.set("backgroundUrl",e))},removeImage(e){e.preventDefault(),n.store.set("backgroundUrl","url()"),a.$chooseButton.removeClass("wpforms-hidden")},chooseImage(e){e.preventDefault(),"library"===n.getSettings().backgroundImage?i.openMediaLibrary():n.stockPhotos.openModal("bg-styles"),i.maybeShowChooseButton()},setImagePreview(e=null){var r=!e||"url()"===e,e=r?"url()":`url(${e})`;a.$imagePreview.css("background-image",e),a.$imagePreview.toggleClass("wpforms-hidden",r),a.$removeButton.toggleClass("wpforms-hidden",r)},maybeShowChooseButton(){var e=n.getSettings();"none"!==e.backgroundImage&&"url()"===e.backgroundUrl?a.$chooseButton.removeClass("wpforms-hidden"):a.$chooseButton.addClass("wpforms-hidden")},openMediaLibrary(){let r=wp.media({multiple:!1,library:{type:"image"}});r.on("select",()=>{var e=r.state().get("selection").first().toJSON();e.url&&n.store.set("backgroundUrl",e.url)}),r.open()},handleSizeFromDimensions(e){var r=n.getSettings(),o=a.$preview.find(".wpforms-container")[0],t=n.common.prepareComplexAttrValues(r.backgroundWidth,"backgroundWidth"),r=n.common.prepareComplexAttrValues(r.backgroundHeight,"backgroundHeight"),s=n.getControls("backgroundSize");"cover"===e?(i.setContainerBackgroundWidth(o,t),i.setContainerBackgroundHeight(o,r),o.style.setProperty("--wpforms-background-size","cover"),s.val("cover")):(o.style.setProperty("--wpforms-background-size",t+" "+r),s.val(t+" "+r)),s.trigger("input")},handleSizeFromHeight(e,r,o){var t=n.common.prepareComplexAttrValues(o.backgroundWidth,"backgroundWidth"),s=n.getControls("backgroundSize");i.setContainerBackgroundHeight(e,r),"cover"!==o.backgroundSizeMode&&(s.val(t+" "+r),e.style.setProperty("--wpforms-background-size",t+" "+r),s.trigger("input"))},handleSizeFromWidth(e,r,o){var t=n.common.prepareComplexAttrValues(o.backgroundWidth,"backgroundWidth"),s=n.common.prepareComplexAttrValues(o.backgroundHeight,"backgroundHeight"),a=n.getControls("backgroundSize");i.setContainerBackgroundWidth(e,t),"cover"!==o.backgroundSizeMode&&(a.val(r+" "+s),e.style.setProperty("--wpforms-background-size",r+" "+s),a.trigger("input"))},setBackgroundColor(e,r){e.style.setProperty("--wpforms-background-color",r)},setBackgroundUrl(e,r){e.style.setProperty("--wpforms-background-url",r)},setContainerBackgroundHeight(e,r){e.style.setProperty("--wpforms-background-height",r)},setContainerBackgroundImage(e,r){"none"===r&&e.style.setProperty("--wpforms-background-url","url()")},setContainerBackgroundPosition(e,r){e.style.setProperty("--wpforms-background-position",r)},setContainerBackgroundRepeat(e,r){e.style.setProperty("--wpforms-background-repeat",r)},setContainerBackgroundWidth(e,r){e.style.setProperty("--wpforms-background-width",r)}};return i}
|
||||
+955
@@ -0,0 +1,955 @@
|
||||
/* global wpf, wpforms_builder_themes, WPFormsBuilder, wpforms_education, WPFormsEducation, WPFormsUtils */
|
||||
|
||||
/**
|
||||
* WPForms Form Builder Themes: Common module.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {Object} document Document object.
|
||||
* @param {Object} window Window object.
|
||||
* @param {jQuery} $ jQuery object.
|
||||
*
|
||||
* @return {Object} Public functions and properties.
|
||||
*/
|
||||
export default function( document, window, $ ) {// eslint-disable-line max-lines-per-function
|
||||
const WPForms = window.WPForms || {};
|
||||
const WPFormsBuilderThemes = WPForms.Admin.Builder.Themes || {};
|
||||
|
||||
/**
|
||||
* Localized data aliases.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
const { isPro, isLicenseActive, isModern, isFullStyles, isLowFormPagesVersion, strings } = wpforms_builder_themes;
|
||||
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const el = {};
|
||||
|
||||
/**
|
||||
* Field dependencies configuration.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const fieldDependencies = {
|
||||
fieldBorderStyle: {
|
||||
none: {
|
||||
disable: [ 'fieldBorderSize', 'fieldBorderColor' ],
|
||||
},
|
||||
},
|
||||
buttonBorderStyle: {
|
||||
none: {
|
||||
disable: [ 'buttonBorderSize', 'buttonBorderColor' ],
|
||||
},
|
||||
},
|
||||
containerBorderStyle: {
|
||||
none: {
|
||||
disable: [ 'containerBorderWidth', 'containerBorderColor' ],
|
||||
},
|
||||
},
|
||||
backgroundImage: {
|
||||
none: {
|
||||
hide: [ 'backgroundPosition', 'backgroundRepeat', 'backgroundSizeMode', 'backgroundWidth', 'backgroundHeight' ],
|
||||
},
|
||||
},
|
||||
backgroundSizeMode: {
|
||||
cover: {
|
||||
hide: [ 'backgroundWidth', 'backgroundHeight' ],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
init() {
|
||||
app.setup();
|
||||
app.events();
|
||||
|
||||
// Maybe show the sidebar after page reload.
|
||||
app.handlePanelSwitch();
|
||||
|
||||
// Init color pickers.
|
||||
app.loadColorPickers();
|
||||
|
||||
// Init settings store.
|
||||
WPFormsBuilderThemes.store.initFromDOM();
|
||||
|
||||
// Subscribe to all settings change.
|
||||
WPFormsBuilderThemes.store.subscribeAll( ( value, key ) => {
|
||||
app.changeStyleSettings( value, key );
|
||||
app.handleFieldDependencies( key, value );
|
||||
} );
|
||||
|
||||
// Render already saved settings.
|
||||
app.renderSavedSettings();
|
||||
|
||||
// Apply initial dependencies.
|
||||
app.applyAllDependencies();
|
||||
|
||||
// Block PRO controls.
|
||||
app.blockProSections();
|
||||
|
||||
// Run checks.
|
||||
app.runChecks();
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
setup() {
|
||||
el.$builder = $( '#wpforms-builder' );
|
||||
el.$settings = $( '.wpforms-panel-content-section-themes' );
|
||||
el.$sidebar = $( '#wpforms-builder-themes-sidebar' );
|
||||
el.$preview = $( '#wpforms-builder-themes-preview' );
|
||||
el.$tabs = $( '#wpforms-builder-themes-sidebar-tabs > a' );
|
||||
|
||||
// Set the custom class to sidebar content for macOS.
|
||||
if ( app.isMac() ) {
|
||||
el.$sidebar.find( '.wpforms-builder-themes-sidebar-content' ).addClass( 'wpforms-is-mac' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
events() {
|
||||
el.$builder
|
||||
.on( 'click', '#wpforms-builder-themes-back', app.handleClosePreviewSidebar )
|
||||
.on( 'click', '.wpforms-panel-sidebar-section-themes', app.handleOpenPreviewSidebar )
|
||||
.on( 'wpformsPanelSwitched', '.wpforms-panel-sidebar-section-themes', app.handlePanelSwitch )
|
||||
.on( 'wpformsPanelSectionSwitch', app.handlePanelSectionSwitch )
|
||||
.on( 'click', '.wpforms-panel-settings-button.active[data-panel="settings"]', app.handleSettingsTabClick );
|
||||
|
||||
el.$tabs.on( 'click', app.handleTabClick );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle sidebar closing when the 'Settings' tab button is clicked.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
handleSettingsTabClick() {
|
||||
if ( el.$sidebar.hasClass( 'wpforms-hidden' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
app.handleClosePreviewSidebar( null );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle field dependencies when a field value changes.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} fieldKey The field key that changed.
|
||||
* @param {string} fieldValue The new field value.
|
||||
*/
|
||||
handleFieldDependencies( fieldKey, fieldValue ) {
|
||||
// After handling the specific field dependency, re-apply all dependencies
|
||||
// to ensure all conditions are properly evaluated with current values.
|
||||
app.applyFieldDependency( fieldKey, fieldValue );
|
||||
app.applyAllDependencies();
|
||||
},
|
||||
|
||||
/**
|
||||
* Apply dependency for a specific field.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} fieldKey The field key that changed.
|
||||
* @param {string} fieldValue The new field value.
|
||||
*/
|
||||
applyFieldDependency( fieldKey, fieldValue ) {
|
||||
if ( ! fieldDependencies[ fieldKey ] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dependencies = fieldDependencies[ fieldKey ];
|
||||
|
||||
// Check each condition for the field.
|
||||
// eslint-disable-next-line complexity
|
||||
Object.keys( dependencies ).forEach( ( conditionValue ) => {
|
||||
const condition = dependencies[ conditionValue ];
|
||||
const shouldApply = fieldValue === conditionValue;
|
||||
|
||||
// Handle disable conditions.
|
||||
if ( condition.disable && shouldApply ) {
|
||||
condition.disable.forEach( ( dependentField ) => {
|
||||
app.disableField( dependentField );
|
||||
} );
|
||||
} else if ( condition.disable ) {
|
||||
condition.disable.forEach( ( dependentField ) => {
|
||||
app.enableField( dependentField );
|
||||
} );
|
||||
}
|
||||
|
||||
// Handle enable conditions.
|
||||
if ( condition.enable && shouldApply ) {
|
||||
condition.enable.forEach( ( dependentField ) => {
|
||||
app.enableField( dependentField );
|
||||
} );
|
||||
} else if ( condition.enable ) {
|
||||
condition.enable.forEach( ( dependentField ) => {
|
||||
app.disableField( dependentField );
|
||||
} );
|
||||
}
|
||||
|
||||
// Handle hide conditions.
|
||||
if ( condition.hide && shouldApply ) {
|
||||
condition.hide.forEach( ( dependentField ) => {
|
||||
app.hideField( dependentField );
|
||||
} );
|
||||
} else if ( condition.hide ) {
|
||||
condition.hide.forEach( ( dependentField ) => {
|
||||
app.showField( dependentField );
|
||||
} );
|
||||
}
|
||||
|
||||
// Handle show conditions.
|
||||
if ( condition.show && shouldApply ) {
|
||||
condition.show.forEach( ( dependentField ) => {
|
||||
app.showField( dependentField );
|
||||
} );
|
||||
} else if ( condition.show ) {
|
||||
condition.show.forEach( ( dependentField ) => {
|
||||
app.hideField( dependentField );
|
||||
} );
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Apply all dependencies based on current settings.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
applyAllDependencies() {
|
||||
const settings = WPFormsBuilderThemes.getSettings();
|
||||
|
||||
Object.keys( fieldDependencies ).forEach( ( fieldKey ) => {
|
||||
const fieldValue = settings[ fieldKey ];
|
||||
if ( fieldValue !== undefined ) {
|
||||
app.applyFieldDependency( fieldKey, fieldValue );
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Disable a field and its wrapper.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} fieldKey The field key to disable.
|
||||
*/
|
||||
disableField( fieldKey ) {
|
||||
const $field = el.$sidebar.find( `[name*="${ fieldKey }"]` );
|
||||
|
||||
if ( $field.length ) {
|
||||
$field.addClass( 'wpforms-builder-themes-disabled' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Enable a field and its wrapper.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} fieldKey The field key to enable.
|
||||
*/
|
||||
enableField( fieldKey ) {
|
||||
const $field = el.$sidebar.find( `[name*="${ fieldKey }"]` );
|
||||
|
||||
if ( $field.length ) {
|
||||
$field.removeClass( 'wpforms-builder-themes-disabled' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide a field and its wrapper.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} fieldKey The field key to hide.
|
||||
*/
|
||||
hideField( fieldKey ) {
|
||||
const $field = el.$sidebar.find( `[name*="${ fieldKey }"]` );
|
||||
const $wrapper = $field.parent().parent().hasClass( 'wpforms-builder-themes-conditional-hide' )
|
||||
? $field.parent().parent()
|
||||
: $field.parent( '.wpforms-panel-field' );
|
||||
|
||||
if ( $field.length ) {
|
||||
$field.prop( 'disabled', true );
|
||||
$wrapper.addClass( 'wpforms-builder-themes-hidden' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Show a field and its wrapper.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} fieldKey The field key to show.
|
||||
*/
|
||||
showField( fieldKey ) {
|
||||
const $field = el.$sidebar.find( `[name*="${ fieldKey }"]` );
|
||||
const $wrapper = $field.parent().parent().hasClass( 'wpforms-builder-themes-conditional-hide' )
|
||||
? $field.parent().parent()
|
||||
: $field.parent( '.wpforms-panel-field' );
|
||||
|
||||
if ( $field.length ) {
|
||||
$field.prop( 'disabled', false );
|
||||
$wrapper.removeClass( 'wpforms-builder-themes-hidden' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle opening the custom settings sidebar.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {Object} event The event object.
|
||||
*/
|
||||
handleOpenPreviewSidebar( event ) {
|
||||
el.$sidebar?.removeClass( 'wpforms-hidden' );
|
||||
event?.preventDefault();
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle closing the custom settings sidebar.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {Object} event The event object.
|
||||
*/
|
||||
handleClosePreviewSidebar( event ) {
|
||||
el.$sidebar?.addClass( 'wpforms-hidden' );
|
||||
event?.preventDefault();
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle panel switch and maybe open the sidebar.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
handlePanelSwitch() {
|
||||
if ( wpf.getQueryString( 'section' ) === 'themes' ) {
|
||||
app.handleOpenPreviewSidebar( null );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle panel section switch and maybe open the sidebar.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {Object} _event The event object.
|
||||
* @param {string} section The section that was switched to.
|
||||
*/
|
||||
handlePanelSectionSwitch( _event, section ) {
|
||||
if ( section === 'themes' ) {
|
||||
app.checkForFormFeatures();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle tabs click.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
*/
|
||||
handleTabClick( e ) {
|
||||
e.preventDefault();
|
||||
el.$tabs.toggleClass( 'active' );
|
||||
$( '.wpforms-builder-themes-sidebar-tab-content' ).toggleClass( 'wpforms-hidden' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a list of the style settings keys.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @return {Array} Settings keys
|
||||
*/
|
||||
getStyleAttributesKeys() {
|
||||
return [
|
||||
'containerPadding',
|
||||
'containerBorderStyle',
|
||||
'containerBorderWidth',
|
||||
'containerBorderRadius',
|
||||
'containerShadowSize',
|
||||
'containerBorderColor',
|
||||
'fieldSize',
|
||||
'fieldBorderStyle',
|
||||
'fieldBorderRadius',
|
||||
'fieldBorderSize',
|
||||
'fieldBackgroundColor',
|
||||
'fieldBorderColor',
|
||||
'fieldTextColor',
|
||||
'fieldMenuColor',
|
||||
'pageBreakColor',
|
||||
'labelSize',
|
||||
'labelColor',
|
||||
'labelSublabelColor',
|
||||
'labelErrorColor',
|
||||
'buttonSize',
|
||||
'buttonBorderStyle',
|
||||
'buttonBorderSize',
|
||||
'buttonBorderRadius',
|
||||
'buttonBackgroundColor',
|
||||
'buttonBorderColor',
|
||||
'buttonTextColor',
|
||||
'backgroundColor',
|
||||
'backgroundPosition',
|
||||
'backgroundUrl',
|
||||
'backgroundRepeat',
|
||||
'backgroundSize',
|
||||
'backgroundSizeMode',
|
||||
'backgroundWidth',
|
||||
'backgroundHeight',
|
||||
'backgroundImage',
|
||||
];
|
||||
},
|
||||
|
||||
/**
|
||||
* Get style handlers.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @return {Object} Style handlers.
|
||||
*/
|
||||
getStyleHandlers() {
|
||||
return {
|
||||
'background-url': WPFormsBuilderThemes.background.setBackgroundUrl,
|
||||
'background-image': WPFormsBuilderThemes.background.setContainerBackgroundImage,
|
||||
'background-position': WPFormsBuilderThemes.background.setContainerBackgroundPosition,
|
||||
'background-repeat': WPFormsBuilderThemes.background.setContainerBackgroundRepeat,
|
||||
'background-color': WPFormsBuilderThemes.background.setBackgroundColor,
|
||||
'background-height': WPFormsBuilderThemes.background.handleSizeFromHeight,
|
||||
'background-width': WPFormsBuilderThemes.background.handleSizeFromWidth,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Change style setting handler.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} settingValue Setting value.
|
||||
* @param {string} settingKey Setting key.
|
||||
*/
|
||||
changeStyleSettings( settingValue, settingKey ) {// eslint-disable-line complexity
|
||||
const wpformsContainer = el.$preview.find( '.wpforms-container' )[ 0 ];
|
||||
|
||||
if ( ! wpformsContainer ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process only styles related settings
|
||||
if ( ! app.getStyleAttributesKeys().includes( settingKey ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const settings = WPFormsBuilderThemes.getSettings();
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
*/
|
||||
const property = settingKey.replace( /[A-Z]/g, ( letter ) => `-${ letter.toLowerCase() }` );
|
||||
settingValue = app.prepareComplexAttrValues( settingValue, settingKey );
|
||||
|
||||
// Check for custom handlers.
|
||||
if ( typeof app.getStyleHandlers()[ property ] === 'function' ) {
|
||||
app.getStyleHandlers()[ property ]( wpformsContainer, settingValue, settings );
|
||||
return;
|
||||
}
|
||||
|
||||
switch ( property ) {
|
||||
case 'field-size':
|
||||
case 'label-size':
|
||||
case 'button-size':
|
||||
case 'container-shadow-size':
|
||||
for ( const key in wpforms_builder_themes.sizes[ property ][ settingValue ] ) {
|
||||
wpformsContainer.style.setProperty(
|
||||
`--wpforms-${ property }-${ key }`,
|
||||
wpforms_builder_themes.sizes[ property ][ settingValue ][ key ],
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'button-background-color':
|
||||
app.maybeUpdateAccentColor( settings.buttonBorderColor, settingValue, wpformsContainer );
|
||||
settingValue = app.maybeSetButtonAltBackgroundColor( settingValue, settings.buttonBorderColor, wpformsContainer );
|
||||
app.maybeSetButtonAltTextColor( settings.buttonTextColor, settingValue, settings.buttonBorderColor, wpformsContainer );
|
||||
wpformsContainer.style.setProperty( `--wpforms-${ property }`, settingValue );
|
||||
|
||||
break;
|
||||
|
||||
case 'button-border-color':
|
||||
app.maybeUpdateAccentColor( settingValue, settings.buttonBackgroundColor, wpformsContainer );
|
||||
app.maybeSetButtonAltTextColor( settings.buttonTextColor, settings.buttonBackgroundColor, settingValue, wpformsContainer );
|
||||
wpformsContainer.style.setProperty( `--wpforms-${ property }`, settingValue );
|
||||
|
||||
break;
|
||||
|
||||
case 'button-text-color':
|
||||
app.maybeSetButtonAltTextColor( settingValue, settings.buttonBackgroundColor, settings.buttonBorderColor, wpformsContainer );
|
||||
wpformsContainer.style.setProperty( `--wpforms-${ property }`, settingValue );
|
||||
|
||||
break;
|
||||
default:
|
||||
wpformsContainer.style.setProperty( `--wpforms-${ property }`, settingValue );
|
||||
wpformsContainer.style.setProperty( `--wpforms-${ property }-spare`, settingValue );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Maybe update accent color.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} color Color value.
|
||||
* @param {string} buttonBackgroundColor Button background color.
|
||||
* @param {Object} container Form container.
|
||||
*/
|
||||
maybeUpdateAccentColor( color, buttonBackgroundColor, container ) {
|
||||
// Setting the CSS property value to the child element overrides the parent property value.
|
||||
const formWrapper = container.querySelector( '#builder-themes-form-preview-wrapper' );
|
||||
|
||||
// Fallback to the default color if the border color is transparent.
|
||||
color = WPFormsUtils.cssColorsUtils.isTransparentColor( color ) ? '#066aab' : color;
|
||||
|
||||
if ( WPFormsUtils.cssColorsUtils.isTransparentColor( buttonBackgroundColor ) ) {
|
||||
formWrapper.style.setProperty( '--wpforms-button-background-color-alt', 'rgba( 0, 0, 0, 0 )' );
|
||||
formWrapper.style.setProperty( '--wpforms-button-background-color', color );
|
||||
} else {
|
||||
container.style.setProperty( '--wpforms-button-background-color-alt', buttonBackgroundColor );
|
||||
formWrapper.style.setProperty( '--wpforms-button-background-color-alt', null );
|
||||
formWrapper.style.setProperty( '--wpforms-button-background-color', null );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Maybe set the button's alternative background color.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} value Setting value.
|
||||
* @param {string} buttonBorderColor Button border color.
|
||||
* @param {Object} container Form container.
|
||||
*
|
||||
* @return {string|*} New background color.
|
||||
*/
|
||||
maybeSetButtonAltBackgroundColor( value, buttonBorderColor, container ) {
|
||||
// Setting the CSS property value to the child element overrides the parent property value.
|
||||
const formWrapper = container.querySelector( '#builder-themes-form-preview-wrapper' );
|
||||
|
||||
formWrapper.style.setProperty( '--wpforms-button-background-color-alt', value );
|
||||
|
||||
if ( WPFormsUtils.cssColorsUtils.isTransparentColor( value ) ) {
|
||||
return WPFormsUtils.cssColorsUtils.isTransparentColor( buttonBorderColor ) ? '#066aab' : buttonBorderColor;
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Maybe set the button's alternative text color.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} value Setting value.
|
||||
* @param {string} buttonBackgroundColor Button background color.
|
||||
* @param {string} buttonBorderColor Button border color.
|
||||
* @param {Object} container Form container.
|
||||
*/
|
||||
maybeSetButtonAltTextColor( value, buttonBackgroundColor, buttonBorderColor, container ) {
|
||||
const formWrapper = container.querySelector( '#builder-themes-form-preview-wrapper' );
|
||||
|
||||
let altColor = null;
|
||||
|
||||
value = value.toLowerCase();
|
||||
|
||||
if (
|
||||
WPFormsUtils.cssColorsUtils.isTransparentColor( value ) ||
|
||||
value === buttonBackgroundColor ||
|
||||
(
|
||||
WPFormsUtils.cssColorsUtils.isTransparentColor( buttonBackgroundColor ) &&
|
||||
value === buttonBorderColor
|
||||
)
|
||||
) {
|
||||
altColor = WPFormsUtils.cssColorsUtils.getContrastColor( buttonBackgroundColor );
|
||||
}
|
||||
|
||||
container.style.setProperty( `--wpforms-button-text-color-alt`, value );
|
||||
formWrapper.style.setProperty( `--wpforms-button-text-color-alt`, altColor );
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepare complex setting values.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string|Object} value Setting value.
|
||||
* @param {string} key Attribute key.
|
||||
*
|
||||
* @return {string|Object} Prepared setting value.
|
||||
*/
|
||||
prepareComplexAttrValues( value, key ) {
|
||||
const pxItems = [
|
||||
'fieldBorderRadius',
|
||||
'fieldBorderSize',
|
||||
'buttonBorderRadius',
|
||||
'buttonBorderSize',
|
||||
'containerPadding',
|
||||
'containerBorderWidth',
|
||||
'containerBorderRadius',
|
||||
'backgroundWidth',
|
||||
'backgroundHeight',
|
||||
];
|
||||
|
||||
if ( pxItems.includes( key ) ) {
|
||||
if ( typeof value === 'number' || ( typeof value === 'string' && ! value.trim().endsWith( 'px' ) ) ) {
|
||||
value = `${ value }px`;
|
||||
}
|
||||
}
|
||||
|
||||
if ( key === 'backgroundUrl' ) {
|
||||
if ( typeof value === 'string' && ! value.trim().startsWith( 'url(' ) ) {
|
||||
value = value ? `url( ${ value } )` : 'url()';
|
||||
}
|
||||
}
|
||||
|
||||
// Remove spaces after/before braces in rgb/rgba colors.
|
||||
value = app.removeRgbaSpaces( value );
|
||||
|
||||
return value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove extra spaces in rgba/rgb values.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} value Setting value.
|
||||
*
|
||||
* @return {string} Prepared setting value.
|
||||
*/
|
||||
removeRgbaSpaces( value ) {
|
||||
if ( typeof value !== 'string' || ! value.includes( 'rgb' ) ) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return value
|
||||
.replace( /\(\s*/g, '(' )
|
||||
.replace( /\s*\)/g, ')' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Render already saved settings.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
renderSavedSettings() {
|
||||
const wpformsContainer = el.$preview.find( '.wpforms-container' )[ 0 ];
|
||||
|
||||
if ( ! wpformsContainer ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const settings = WPFormsBuilderThemes.getSettings();
|
||||
|
||||
_.each( settings, ( value, key ) => {
|
||||
app.changeStyleSettings( value, key );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Custom loader for color pickers.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
loadColorPickers() {
|
||||
WPFormsBuilder.loadColorPickers( el.$sidebar, {
|
||||
position: 'top left',
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Disable PRO sections.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
blockProSections() {
|
||||
if ( isPro && isLicenseActive ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $proSectionsHeadings = $( '.wpforms-add-fields-heading[data-group="background_styles"], .wpforms-add-fields-heading[data-group="container_styles"]' );
|
||||
const proSections = $( '.wpforms-builder-themes-pro-section' );
|
||||
|
||||
// Disable sections and show the PRO badge.
|
||||
proSections.addClass( 'wpforms-builder-themes-disabled-pro' );
|
||||
$proSectionsHeadings.addClass( 'wpforms-builder-themes-pro-blocked' );
|
||||
|
||||
// Disable clicks on blocked sections.
|
||||
proSections.off( 'click' ).on( 'click', app.handleProSectionClick );
|
||||
},
|
||||
|
||||
/**
|
||||
* Disable all sections.
|
||||
*
|
||||
* @since 1.9.7
|
||||
* @param {boolean} unblock Need to unblock status.
|
||||
*/
|
||||
blockAllSections( unblock = false ) {
|
||||
const sections = el.$sidebar.find( '.wpforms-add-fields-buttons, .wpforms-builder-themes-sidebar-advanced' );
|
||||
|
||||
// Disable/Enable all sections.
|
||||
if ( ! unblock ) {
|
||||
sections.addClass( 'wpforms-builder-themes-disabled' );
|
||||
} else {
|
||||
sections.removeClass( 'wpforms-builder-themes-disabled' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle the PRO section click.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
handleProSectionClick() {
|
||||
const section = $( this ).prev( 'a' ).data( 'group' )?.replace( '_styles', '' );
|
||||
|
||||
if ( ! isPro ) {
|
||||
app.showProModal( section, strings.pro_sections[ section ] );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! isLicenseActive ) {
|
||||
app.showLicenseModal( strings.pro_sections[ section ], strings.pro_sections[ section ], 'pro-section' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the educational popup for users with no Pro license.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} panel Panel slug.
|
||||
* @param {string} feature Feature name.
|
||||
*/
|
||||
showProModal( panel, feature ) {
|
||||
const type = 'pro';
|
||||
const message = wpforms_education.upgrade[ type ].message_plural.replace( /%name%/g, feature );
|
||||
const utmContent = {
|
||||
container: 'General Container Styles',
|
||||
background: 'General Background Styles',
|
||||
themes: 'General Pro Themes',
|
||||
};
|
||||
|
||||
$.alert( {
|
||||
backgroundDismiss: true,
|
||||
title: feature + ' ' + wpforms_education.upgrade[ type ].title_plural,
|
||||
icon: 'fa fa-lock',
|
||||
content: message,
|
||||
boxWidth: '550px',
|
||||
theme: 'modern,wpforms-education',
|
||||
closeIcon: true,
|
||||
onOpenBefore: function() { // eslint-disable-line object-shorthand
|
||||
this.$btnc.after( '<div class="discount-note">' + wpforms_education.upgrade_bonus + '</div>' );
|
||||
this.$btnc.after( wpforms_education.upgrade[ type ].doc.replace( /%25name%25/g, 'AP - ' + feature ) );
|
||||
this.$body.find( '.jconfirm-content' ).addClass( 'lite-upgrade' );
|
||||
},
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_education.upgrade[ type ].button,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action: () => {
|
||||
window.open( WPFormsEducation.core.getUpgradeURL( utmContent[ panel ], type ), '_blank' );
|
||||
WPFormsEducation.core.upgradeModalThankYou( type );
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Open license modal.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} feature Feature name.
|
||||
* @param {string} fieldName Field name.
|
||||
* @param {string} utmContent UTM content.
|
||||
*/
|
||||
showLicenseModal( feature, fieldName, utmContent ) {
|
||||
WPFormsEducation.proCore.licenseModal( feature, fieldName, utmContent );
|
||||
},
|
||||
|
||||
/**
|
||||
* Run custom checks.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
runChecks() {
|
||||
app.checkForClassicStyles();
|
||||
|
||||
if ( isPro && isLicenseActive && isModern && isFullStyles ) {
|
||||
app.checkForFormFeatures();
|
||||
}
|
||||
|
||||
app.checkForOldFP();
|
||||
},
|
||||
|
||||
/**
|
||||
* Conditionally show/hide classic styles notice and block/unblock controls.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
checkForClassicStyles() {
|
||||
const $notice = $( '.wpforms-builder-themes-style-notice' );
|
||||
const $previewNotice = $( '.wpforms-builder-themes-preview-notice' );
|
||||
|
||||
if ( ! isModern || ! isFullStyles ) {
|
||||
app.blockAllSections();
|
||||
$notice.removeClass( 'wpforms-hidden' );
|
||||
$previewNotice.addClass( 'wpforms-hidden' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check both Lead Forms and Conversational Forms states and update the UI accordingly.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
checkForFormFeatures() {
|
||||
const $LFSwitch = $( '#wpforms-panel-field-lead_forms-enable' );
|
||||
const $CFSwitch = $( '#wpforms-panel-field-settings-conversational_forms_enable' );
|
||||
const isLFEnabled = $LFSwitch.prop( 'checked' ) ?? false;
|
||||
const isCFEnabled = $CFSwitch.prop( 'checked' ) ?? false;
|
||||
const $LFNotice = $( '.wpforms-builder-themes-lf-notice' );
|
||||
const $CFNotice = $( '.wpforms-builder-themes-cf-notice' );
|
||||
const $previewNotice = $( '.wpforms-builder-themes-preview-notice' );
|
||||
|
||||
// Handle Lead Forms notice visibility
|
||||
if ( isLFEnabled ) {
|
||||
$LFNotice.removeClass( 'wpforms-hidden' );
|
||||
} else {
|
||||
$LFNotice.addClass( 'wpforms-hidden' );
|
||||
}
|
||||
|
||||
// Handle Conversational Forms notice visibility
|
||||
if ( isCFEnabled ) {
|
||||
$CFNotice.removeClass( 'wpforms-hidden' );
|
||||
} else {
|
||||
$CFNotice.addClass( 'wpforms-hidden' );
|
||||
}
|
||||
|
||||
// If either feature is enabled, hide preview and block sections
|
||||
if ( isLFEnabled || isCFEnabled ) {
|
||||
$previewNotice.addClass( 'wpforms-hidden' );
|
||||
el.$preview.addClass( 'wpforms-hidden' );
|
||||
app.blockAllSections();
|
||||
} else {
|
||||
// Only if both features are disabled, show preview and unblock sections
|
||||
el.$preview.removeClass( 'wpforms-hidden' );
|
||||
if ( isModern && isFullStyles ) {
|
||||
app.blockAllSections( true );
|
||||
$previewNotice.removeClass( 'wpforms-hidden' );
|
||||
}
|
||||
}
|
||||
|
||||
// Set up event handlers if they haven't been set up yet
|
||||
app.setupFormFeatureEventHandlers();
|
||||
},
|
||||
|
||||
/**
|
||||
* Set up event handlers for Lead Forms and Conversational Forms switches.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
setupFormFeatureEventHandlers() {
|
||||
// Set up notice link handlers
|
||||
$( '.wpforms-builder-themes-lf-notice a' ).off( 'click', app.openLFSettings ).on( 'click', app.openLFSettings );
|
||||
$( '.wpforms-builder-themes-cf-notice a' ).off( 'click', app.openCFSettings ).on( 'click', app.openCFSettings );
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows the notice if the Form Pages addons version is low.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
checkForOldFP() {
|
||||
const $FPContent = $( '#wpforms-form-pages-content-block' );
|
||||
const $notice = $( '#wpforms-page-forms-fbst-notice' );
|
||||
|
||||
if ( $FPContent.length ) {
|
||||
if ( isLowFormPagesVersion ) {
|
||||
$FPContent.prepend( $notice );
|
||||
$notice.removeClass( 'wpforms-hidden' );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the Lead Forms settings page.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {Object} event Event object.
|
||||
*/
|
||||
openLFSettings( event ) {
|
||||
app.handleClosePreviewSidebar( event );
|
||||
|
||||
$( 'a.wpforms-panel-sidebar-section-lead_forms' ).click();
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the Conversational Forms settings page.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {Object} event Event object.
|
||||
*/
|
||||
openCFSettings( event ) {
|
||||
app.handleClosePreviewSidebar( event );
|
||||
|
||||
$( 'a.wpforms-panel-sidebar-section-conversational_forms' ).click();
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine if the user is on a Mac.
|
||||
*
|
||||
* @return {boolean} True if the user is on a Mac.
|
||||
*/
|
||||
isMac() {
|
||||
return navigator.userAgent.includes( 'Macintosh' );
|
||||
},
|
||||
};
|
||||
|
||||
return app;
|
||||
}
|
||||
Vendored
Executable
+1
File diff suppressed because one or more lines are too long
+356
@@ -0,0 +1,356 @@
|
||||
/* global wpforms_builder_themes */
|
||||
|
||||
/**
|
||||
* WPForms Form Builder Themes: Stock Photos module.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {Object} document Document object.
|
||||
* @param {Object} window Window object.
|
||||
* @param {jQuery} $ jQuery object.
|
||||
*
|
||||
* @return {Object} Public functions and properties.
|
||||
*/
|
||||
// eslint-disable-next-line max-lines-per-function
|
||||
export default function( document, window, $ ) { // eslint-disable-line no-unused-vars
|
||||
const WPForms = window.WPForms || {};
|
||||
const WPFormsBuilderThemes = WPForms.Admin.Builder.Themes || {};
|
||||
|
||||
/**
|
||||
* Localized data aliases.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
const strings = wpforms_builder_themes.strings;
|
||||
const routeNamespace = wpforms_builder_themes.route_namespace;
|
||||
const pictureUrlPath = wpforms_builder_themes.stockPhotos?.urlPath;
|
||||
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const el = {};
|
||||
|
||||
/**
|
||||
* Spinner markup.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
const spinner = '<i class="wpforms-loading-spinner wpforms-loading-white wpforms-loading-inline"></i>';
|
||||
|
||||
/**
|
||||
* Runtime state.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const state = {};
|
||||
|
||||
/**
|
||||
* Stock photos pictures' list.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @type {Array}
|
||||
*/
|
||||
let pictures = wpforms_builder_themes.stockPhotos?.pictures;
|
||||
|
||||
/**
|
||||
* Stock photos picture selector markup.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
let picturesMarkup = '';
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
init() {
|
||||
app.setup();
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
setup() {
|
||||
el.$builder = $( '#wpforms-builder' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
events() {
|
||||
},
|
||||
|
||||
/**
|
||||
* Open stock photos modal.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} from From where the modal was triggered, `themes` or `bg-styles`.
|
||||
*/
|
||||
openModal( from ) {
|
||||
if ( app.isPicturesAvailable() ) {
|
||||
app.picturesModal();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
app.installModal( from );
|
||||
},
|
||||
|
||||
/**
|
||||
* Open stock photos install modal on a select theme.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} themeSlug The theme slug.
|
||||
*/
|
||||
onSelectTheme( themeSlug ) {
|
||||
const themesModule = WPFormsBuilderThemes.themes;
|
||||
|
||||
if ( app.isPicturesAvailable() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check only WPForms themes.
|
||||
if ( ! themesModule?.isWPFormsTheme( themeSlug ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const theme = themesModule?.getTheme( themeSlug );
|
||||
const bgUrl = theme.settings?.backgroundUrl;
|
||||
|
||||
if ( bgUrl?.length && bgUrl !== 'url()' ) {
|
||||
app.installModal( 'themes' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Open a modal prompting to download and install the Stock Photos.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} from From where the modal was triggered, `themes` or `bg-styles`.
|
||||
*/
|
||||
installModal( from ) {
|
||||
const installStr = from === 'themes' ? strings.stockInstallTheme : strings.stockInstallBg;
|
||||
|
||||
$.confirm( {
|
||||
title: strings.heads_up,
|
||||
content: installStr + ' ' + strings.stockInstall,
|
||||
icon: 'wpforms-exclamation-circle',
|
||||
type: 'orange wpforms-builder-themes-modal',
|
||||
buttons: {
|
||||
continue: {
|
||||
text: strings.continue,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action() {
|
||||
// noinspection JSUnresolvedReference
|
||||
this.$$continue.prop( 'disabled', true )
|
||||
.html( spinner + strings.installing );
|
||||
|
||||
// noinspection JSUnresolvedReference
|
||||
this.$$cancel
|
||||
.prop( 'disabled', true );
|
||||
|
||||
app.install( this, from );
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: strings.cancel,
|
||||
keys: [ 'esc' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Display the modal window with an error message.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} error Error message.
|
||||
*/
|
||||
errorModal( error ) {
|
||||
$.alert( {
|
||||
title: strings.uhoh,
|
||||
content: error || strings.commonError,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'red',
|
||||
buttons: {
|
||||
cancel: {
|
||||
text : strings.close,
|
||||
btnClass: 'btn-confirm',
|
||||
keys : [ 'enter' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Display the modal window with pictures.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
picturesModal() {
|
||||
state.picturesModal = $.alert( {
|
||||
title : `${ strings.picturesTitle }<p>${ strings.picturesSubTitle }</p>`,
|
||||
content: app.getPictureMarkup(),
|
||||
type: 'picture-selector wpforms-builder-themes-modal',
|
||||
boxWidth: '800px',
|
||||
closeIcon: true,
|
||||
animation: 'opacity',
|
||||
closeAnimation: 'opacity',
|
||||
buttons: false,
|
||||
onOpen() {
|
||||
this.$content
|
||||
.off( 'click' )
|
||||
.on( 'click', '.wpforms-builder-stock-photos-picture', app.selectPicture );
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Install stock photos.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {Object} modal The jQuery-confirm a modal window object.
|
||||
* @param {string} from From where the modal was triggered, `themes` or `bg-styles`.
|
||||
*/
|
||||
install( modal, from ) {
|
||||
// If a fetch is already in progress, exit the function.
|
||||
if ( state.isInstalling ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the flag to true indicating a fetch is in progress.
|
||||
state.isInstalling = true;
|
||||
|
||||
try {
|
||||
// Fetch themes data.
|
||||
wp.apiFetch( {
|
||||
path: routeNamespace + 'stock-photos/install/',
|
||||
method: 'POST',
|
||||
cache: 'no-cache',
|
||||
} ).then( ( response ) => {
|
||||
if ( ! response.result ) {
|
||||
app.errorModal( response.error );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the pictures' data.
|
||||
pictures = response.pictures || [];
|
||||
|
||||
// Update the theme or open the picture selector modal.
|
||||
if ( from === 'themes' ) {
|
||||
WPFormsBuilderThemes.store.set( 'backgroundUrl', 'url()' );
|
||||
WPFormsBuilderThemes.themes.setFormTheme( WPFormsBuilderThemes.store.get( 'wpformsTheme' ) );
|
||||
} else {
|
||||
app.picturesModal();
|
||||
}
|
||||
} ).catch( ( error ) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error( error?.message );
|
||||
app.errorModal( `<p>${ strings.commonError }</p><p>${ error?.message }</p>` );
|
||||
} ).finally( () => {
|
||||
state.isInstalling = false;
|
||||
|
||||
// Close the modal window.
|
||||
modal.close();
|
||||
} );
|
||||
} catch ( error ) {
|
||||
state.isInstalling = false;
|
||||
// eslint-disable-next-line no-console
|
||||
console.error( error );
|
||||
app.errorModal( strings.commonError + '<br>' + error );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Detect whether pictures' data available.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @return {boolean} True if pictures' data available, false otherwise.
|
||||
*/
|
||||
isPicturesAvailable() {
|
||||
return Boolean( pictures?.length );
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate the pictures' selector markup.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @return {string} Pictures' selector markup.
|
||||
*/
|
||||
getPictureMarkup() {
|
||||
if ( ! app.isPicturesAvailable() ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( picturesMarkup !== '' ) {
|
||||
return picturesMarkup;
|
||||
}
|
||||
|
||||
pictures.forEach( ( picture ) => {
|
||||
const pictureUrl = pictureUrlPath + picture;
|
||||
|
||||
picturesMarkup += `<div class="wpforms-builder-stock-photos-picture"
|
||||
data-url="${ pictureUrl }"
|
||||
style="background-image: url( '${ pictureUrl }' )"
|
||||
></div>`;
|
||||
} );
|
||||
|
||||
picturesMarkup = `<div class="wpforms-builder-stock-photos-pictures-wrap">${ picturesMarkup }</div>`;
|
||||
|
||||
return picturesMarkup;
|
||||
},
|
||||
|
||||
/**
|
||||
* Select picture event handler.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
selectPicture() {
|
||||
const pictureUrl = $( this ).data( 'url' );
|
||||
|
||||
// Update the settings.
|
||||
WPFormsBuilderThemes.store.set( 'backgroundUrl', pictureUrl );
|
||||
|
||||
// Close the modal window.
|
||||
state.picturesModal?.close();
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
return app;
|
||||
}
|
||||
Vendored
Executable
+4
@@ -0,0 +1,4 @@
|
||||
export default function(e,t,s){let r=(t.WPForms||{}).Admin.Builder.Themes||{},o=wpforms_builder_themes.strings,l=wpforms_builder_themes.route_namespace,i=wpforms_builder_themes.stockPhotos?.urlPath,n={},c={},a=wpforms_builder_themes.stockPhotos?.pictures,u="",p={init(){p.setup(),p.events()},setup(){n.$builder=s("#wpforms-builder")},events(){},openModal(e){p.isPicturesAvailable()?p.picturesModal():p.installModal(e)},onSelectTheme(e){var t=r.themes;p.isPicturesAvailable()||t?.isWPFormsTheme(e)&&(t=(t?.getTheme(e)).settings?.backgroundUrl)?.length&&"url()"!==t&&p.installModal("themes")},installModal(e){var t="themes"===e?o.stockInstallTheme:o.stockInstallBg;s.confirm({title:o.heads_up,content:t+" "+o.stockInstall,icon:"wpforms-exclamation-circle",type:"orange wpforms-builder-themes-modal",buttons:{continue:{text:o.continue,btnClass:"btn-confirm",keys:["enter"],action(){return this.$$continue.prop("disabled",!0).html('<i class="wpforms-loading-spinner wpforms-loading-white wpforms-loading-inline"></i>'+o.installing),this.$$cancel.prop("disabled",!0),p.install(this,e),!1}},cancel:{text:o.cancel,keys:["esc"]}}})},errorModal(e){s.alert({title:o.uhoh,content:e||o.commonError,icon:"fa fa-exclamation-circle",type:"red",buttons:{cancel:{text:o.close,btnClass:"btn-confirm",keys:["enter"]}}})},picturesModal(){c.picturesModal=s.alert({title:`${o.picturesTitle}<p>${o.picturesSubTitle}</p>`,content:p.getPictureMarkup(),type:"picture-selector wpforms-builder-themes-modal",boxWidth:"800px",closeIcon:!0,animation:"opacity",closeAnimation:"opacity",buttons:!1,onOpen(){this.$content.off("click").on("click",".wpforms-builder-stock-photos-picture",p.selectPicture)}})},install(e,t){if(!c.isInstalling){c.isInstalling=!0;try{wp.apiFetch({path:l+"stock-photos/install/",method:"POST",cache:"no-cache"}).then(e=>{e.result?(a=e.pictures||[],"themes"===t?(r.store.set("backgroundUrl","url()"),r.themes.setFormTheme(r.store.get("wpformsTheme"))):p.picturesModal()):p.errorModal(e.error)}).catch(e=>{console.error(e?.message),p.errorModal(`<p>${o.commonError}</p><p>${e?.message}</p>`)}).finally(()=>{c.isInstalling=!1,e.close()})}catch(e){c.isInstalling=!1,console.error(e),p.errorModal(o.commonError+"<br>"+e)}}},isPicturesAvailable(){return Boolean(a?.length)},getPictureMarkup(){return p.isPicturesAvailable()?(""===u&&(a.forEach(e=>{e=i+e;u+=`<div class="wpforms-builder-stock-photos-picture"
|
||||
data-url="${e}"
|
||||
style="background-image: url( '${e}' )"
|
||||
></div>`}),u=`<div class="wpforms-builder-stock-photos-pictures-wrap">${u}</div>`),u):""},selectPicture(){var e=s(this).data("url");r.store.set("backgroundUrl",e),c.picturesModal?.close()}};return p}
|
||||
+908
@@ -0,0 +1,908 @@
|
||||
/* global wpforms_builder_themes */
|
||||
|
||||
/**
|
||||
* WPForms Form Builder Themes: Theme module.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {Object} document Document object.
|
||||
* @param {Object} window Window object.
|
||||
* @param {jQuery} $ jQuery object.
|
||||
*
|
||||
* @return {Object} Public functions and properties.
|
||||
*/
|
||||
export default function( document, window, $ ) { // eslint-disable-line max-lines-per-function
|
||||
const WPForms = window.WPForms || {};
|
||||
const WPFormsBuilderThemes = WPForms.Admin.Builder.Themes || {};
|
||||
|
||||
/**
|
||||
* Localized data aliases.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
const { isAdmin, isPro, isLicenseActive, strings, route_namespace: routeNamespace } = wpforms_builder_themes;
|
||||
|
||||
/**
|
||||
* Runtime state.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const state = {};
|
||||
|
||||
/**
|
||||
* Themes data.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const themesData = {
|
||||
wpforms: null,
|
||||
custom: null,
|
||||
};
|
||||
|
||||
/**
|
||||
* Enabled themes.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
let enabledThemes = null;
|
||||
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const el = {};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
init() {
|
||||
app.fetchThemesData();
|
||||
app.setup();
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
setup() {
|
||||
el.$builder = $( '#wpforms-builder' );
|
||||
el.$themesControl = el.$builder.find( '.wpforms-builder-themes-control' );
|
||||
el.$customThemeRenamer = el.$builder.find( '#wpforms-panel-field-themes-themeName-wrap' );
|
||||
el.$customThemeRemover = el.$builder.find( '#wpforms-builder-themer-remove-theme' );
|
||||
el.$window = $( window );
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
events() {
|
||||
el.$window.on( 'wpformsBuilderThemesDataLoaded', app.themesControlSetup );
|
||||
el.$builder.on( 'wpformsSaved', app.saveCustomThemes );
|
||||
},
|
||||
|
||||
/**
|
||||
* Set up the Themes Select control.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
themesControlSetup() {
|
||||
// Debounce custom themes update and creation.
|
||||
const debouncedMaybeCreate = _.debounce( ( key ) => {
|
||||
app.maybeCreateCustomTheme();
|
||||
app.maybeUpdateCustomTheme( key );
|
||||
}, 300 );
|
||||
|
||||
// Listen for all settings changes.
|
||||
WPFormsBuilderThemes.store.subscribeAll( ( value, key ) => {
|
||||
const allowedKeys = WPFormsBuilderThemes.common.getStyleAttributesKeys();
|
||||
if ( ! allowedKeys.includes( key ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
debouncedMaybeCreate( key );
|
||||
} );
|
||||
|
||||
// Listen for the theme name change.
|
||||
WPFormsBuilderThemes.store.subscribe( 'themeName', ( value ) => {
|
||||
app.changeThemeName( value );
|
||||
app.updateThemesList();
|
||||
} );
|
||||
|
||||
// Listen for the isCustomTheme setting change.
|
||||
WPFormsBuilderThemes.store.subscribe( 'isCustomTheme', () => {
|
||||
app.toggleCustomThemeSettings();
|
||||
} );
|
||||
|
||||
// Check if the selected theme exists. If no, create a new one.
|
||||
app.maybeCreateCustomTheme();
|
||||
|
||||
app.toggleCustomThemeSettings();
|
||||
app.updateThemesList();
|
||||
},
|
||||
|
||||
/**
|
||||
* Update themes list.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
updateThemesList() {
|
||||
const selectedTheme = WPFormsBuilderThemes.store.get( 'wpformsTheme' ) ?? 'default';
|
||||
|
||||
// Get all themes.
|
||||
const html = app.getThemesListMarkup( selectedTheme );
|
||||
|
||||
el.$themesControl.html( html );
|
||||
|
||||
app.addThemesEvents();
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the Themes control markup.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} selectedTheme Selected theme slug.
|
||||
*
|
||||
* @return {string} Themes items HTML.
|
||||
*/
|
||||
getThemesListMarkup( selectedTheme ) {
|
||||
if ( ! themesData.wpforms ) {
|
||||
app.fetchThemesData();
|
||||
|
||||
// Return markup with an error message if themes are not available.
|
||||
return `<div class="wpforms-no-themes">${ strings.themes_error }</div>`;
|
||||
}
|
||||
|
||||
const allThemes = app.getAllThemes();
|
||||
|
||||
if ( ! allThemes ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const themes = Object.keys( allThemes );
|
||||
let theme, firstThemeSlug;
|
||||
let html = '';
|
||||
let itemsHtml = '';
|
||||
|
||||
if ( ! app.isWPFormsTheme( selectedTheme ) ) {
|
||||
firstThemeSlug = selectedTheme;
|
||||
|
||||
itemsHtml += app.getThemesItemMarkup( app.getTheme( firstThemeSlug ), firstThemeSlug, firstThemeSlug );
|
||||
}
|
||||
|
||||
for ( const key in themes ) {
|
||||
const slug = themes[ key ];
|
||||
|
||||
// Skip the first theme.
|
||||
if ( firstThemeSlug && firstThemeSlug === slug ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ensure that all the theme settings are present.
|
||||
theme = { ...allThemes.default, ...( allThemes[ slug ] || {} ) };
|
||||
theme.settings = { ...allThemes.default.settings, ...( theme.settings || {} ) };
|
||||
|
||||
itemsHtml += app.getThemesItemMarkup( theme, slug, selectedTheme );
|
||||
}
|
||||
|
||||
html = `<div role="radiogroup" class="wpforms-builder-themes-radio-group">
|
||||
${ itemsHtml }
|
||||
</div>`;
|
||||
|
||||
return html;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the theme item markup.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {Object} theme Theme data.
|
||||
* @param {string} slug Theme slug.
|
||||
* @param {string} selectedTheme Selected theme slug.
|
||||
*
|
||||
* @return {string} Theme item HTML.
|
||||
*/
|
||||
getThemesItemMarkup( theme, slug, selectedTheme ) {
|
||||
if ( ! theme ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const title = theme.name?.length > 0 ? theme.name : strings.theme_noname;
|
||||
let radioClasses = 'wpforms-builder-themes-radio ';
|
||||
const buttonClass = slug === selectedTheme ? 'is-active' : '';
|
||||
|
||||
radioClasses += app.isDisabledTheme( slug ) ? 'wpforms-builder-themes-radio-disabled' : ' wpforms-builder-themes-radio-enabled';
|
||||
|
||||
return `<button type="button" class="${ buttonClass }" value="${ slug }" role="radio">
|
||||
<div class="wpforms-builder-themes-radio ${ radioClasses }">
|
||||
<div class="wpforms-builder-themes-radio-title">${ title }</div>
|
||||
</div>
|
||||
|
||||
<div class="wpforms-builder-themes-indicators">
|
||||
<span class="component-color-indicator" title="${ strings.button_background }" style="background: ${ theme.settings.buttonBackgroundColor };" data-index="0"></span>
|
||||
<span class="component-color-indicator" title="${ strings.button_text }" style="background: ${ theme.settings.buttonTextColor }" data-index="1"></span>
|
||||
<span class="component-color-indicator" title="${ strings.field_label }" style="background: ${ theme.settings.labelColor };" data-index="2"></span>
|
||||
<span class="component-color-indicator" title="${ strings.field_sublabel } " style="background: ${ theme.settings.labelSublabelColor };" data-index="3"></span>
|
||||
<span class="component-color-indicator" title="${ strings.field_border }" style="background: ${ theme.settings.fieldBorderColor };" data-index="4"></span>
|
||||
</div>
|
||||
</button>`;
|
||||
},
|
||||
|
||||
/**
|
||||
* Show or hide the custom theme rename input.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
toggleCustomThemeSettings() {
|
||||
if ( ! isAdmin ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const value = WPFormsBuilderThemes.store.get( 'isCustomTheme' ) ?? '';
|
||||
const shouldShow = value === 'true';
|
||||
|
||||
el.$customThemeRenamer.toggleClass( 'wpforms-hidden', ! shouldShow );
|
||||
el.$customThemeRemover.toggleClass( 'wpforms-hidden', ! shouldShow );
|
||||
},
|
||||
|
||||
/**
|
||||
* On settings change event handler.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
addThemesEvents() {
|
||||
const $radioButtons = el.$themesControl.find( '[role="radio"]' );
|
||||
|
||||
// Add event listeners to the radio buttons.
|
||||
$radioButtons.off( 'click' ).on( 'click', function() {
|
||||
$radioButtons.removeClass( 'is-active' );
|
||||
|
||||
$( this ).addClass( 'is-active' );
|
||||
|
||||
const selectedValue = $( this ).val();
|
||||
|
||||
app.selectTheme( selectedValue );
|
||||
} );
|
||||
|
||||
// Add event listeners to the theme delete button.
|
||||
el.$customThemeRemover
|
||||
.off( 'click' )
|
||||
.on( 'click', app.deleteThemeModal );
|
||||
},
|
||||
|
||||
/**
|
||||
* Select theme event handler.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} value New attribute value.
|
||||
*/
|
||||
selectTheme( value ) {
|
||||
if ( ! app.setFormTheme( value ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
app.onSelectThemeWithBG( value );
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the form theme.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} themeSlug The theme slug.
|
||||
*
|
||||
* @return {boolean} True on success.
|
||||
*/
|
||||
setFormTheme( themeSlug ) {
|
||||
if ( app.maybeDisplayUpgradeModal( themeSlug ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const theme = app.getTheme( themeSlug );
|
||||
|
||||
if ( ! theme?.settings ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const attributes = Object.keys( theme.settings );
|
||||
const isCustomTheme = !! themesData.custom[ themeSlug ];
|
||||
|
||||
// Set the theme settings.
|
||||
WPFormsBuilderThemes.store.set( 'wpformsTheme', themeSlug );
|
||||
WPFormsBuilderThemes.store.set( 'isCustomTheme', isCustomTheme ? 'true' : '' );
|
||||
WPFormsBuilderThemes.store.set( 'themeName', isCustomTheme ? themesData.custom[ themeSlug ].name : '' );
|
||||
|
||||
// Clean up the settings.
|
||||
const cleanSettings = {};
|
||||
|
||||
for ( const key in attributes ) {
|
||||
const attr = attributes[ key ];
|
||||
const value = theme.settings[ attr ];
|
||||
|
||||
cleanSettings[ attr ] = typeof value === 'string'
|
||||
? value.replace( /px$/, '' )
|
||||
: value;
|
||||
}
|
||||
|
||||
// Update the theme settings.
|
||||
app.updateStylesAtts( cleanSettings );
|
||||
|
||||
//Reinit color pickers.
|
||||
WPFormsBuilderThemes.common.loadColorPickers();
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Open stock photos install modal on the select theme.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} themeSlug The theme slug.
|
||||
*/
|
||||
onSelectThemeWithBG( themeSlug ) {
|
||||
if ( WPFormsBuilderThemes.stockPhotos.isPicturesAvailable() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check only WPForms themes.
|
||||
if ( ! app.isWPFormsTheme( themeSlug ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Object|null}
|
||||
* @property {Object|null} settings Settings.
|
||||
*/
|
||||
const theme = app.getTheme( themeSlug );
|
||||
const bgUrl = theme.settings?.backgroundUrl;
|
||||
|
||||
if ( bgUrl?.length && bgUrl !== 'url()' ) {
|
||||
WPFormsBuilderThemes.stockPhotos.installModal( 'themes' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update styles atts.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {Object} themeSettings Theme settings.
|
||||
*/
|
||||
updateStylesAtts( themeSettings ) {
|
||||
const allowedKeys = WPFormsBuilderThemes.common.getStyleAttributesKeys();
|
||||
const validSettings = {};
|
||||
|
||||
for ( const key in themeSettings ) {
|
||||
if ( ! allowedKeys.includes( key ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let value = themeSettings[ key ];
|
||||
|
||||
if ( key === 'backgroundUrl' && typeof value === 'string' ) {
|
||||
value = app.getBackgroundUrl( value );
|
||||
}
|
||||
|
||||
validSettings[ key ] = value;
|
||||
}
|
||||
|
||||
// Update the settings.
|
||||
if ( Object.keys( validSettings ).length ) {
|
||||
Object.entries( validSettings ).forEach( ( [ key, value ] ) => {
|
||||
WPFormsBuilderThemes.store.set( key, value );
|
||||
} );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Extract the background URL from the string.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} value Background value.
|
||||
*
|
||||
* @return {string} Extracted background image url.
|
||||
*/
|
||||
getBackgroundUrl( value ) {
|
||||
const match = value.match( /^url\(\s*['"]?(.*?)['"]?\s*\)$/i );
|
||||
return match?.[ 1 ] || 'url()';
|
||||
},
|
||||
|
||||
/**
|
||||
* Get all themes data.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @return {Object} Themes data.
|
||||
*/
|
||||
getAllThemes() {
|
||||
return { ...( themesData.custom || {} ), ...( themesData.wpforms || {} ) };
|
||||
},
|
||||
|
||||
/**
|
||||
* Get theme data.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} slug Theme slug.
|
||||
*
|
||||
* @return {Object|null} Theme settings.
|
||||
*/
|
||||
getTheme( slug ) {
|
||||
return app.getAllThemes()[ slug ] || null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get enabled themes data.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @return {Object} Themes data.
|
||||
*/
|
||||
getEnabledThemes() {
|
||||
if ( enabledThemes ) {
|
||||
return enabledThemes;
|
||||
}
|
||||
|
||||
const allThemes = app.getAllThemes();
|
||||
|
||||
if ( isPro && isLicenseActive ) {
|
||||
return allThemes;
|
||||
}
|
||||
|
||||
enabledThemes = Object.keys( allThemes ).reduce( ( acc, key ) => {
|
||||
if ( allThemes[ key ].settings?.fieldSize && ! allThemes[ key ].disabled ) {
|
||||
acc[ key ] = allThemes[ key ];
|
||||
}
|
||||
return acc;
|
||||
}, {} );
|
||||
|
||||
return enabledThemes;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update enabled themes.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} slug Theme slug.
|
||||
* @param {Object} theme Theme settings.
|
||||
*/
|
||||
updateEnabledThemes( slug, theme ) {
|
||||
if ( ! enabledThemes ) {
|
||||
return;
|
||||
}
|
||||
|
||||
enabledThemes = {
|
||||
...enabledThemes,
|
||||
[ slug ]: theme,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether the theme is disabled.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} slug Theme slug.
|
||||
*
|
||||
* @return {boolean} True if the theme is disabled.
|
||||
*/
|
||||
isDisabledTheme( slug ) {
|
||||
return ! app.getEnabledThemes()?.[ slug ];
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether the theme is one of the WPForms themes.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} slug Theme slug.
|
||||
*
|
||||
* @return {boolean} True if the theme is one of the WPForms themes.
|
||||
*/
|
||||
isWPFormsTheme( slug ) {
|
||||
return Boolean( themesData.wpforms[ slug ]?.settings );
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch themes data from Rest API.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
fetchThemesData() {
|
||||
// If a fetch is already in progress, exit the function.
|
||||
if ( state.isFetchingThemes || themesData.wpforms ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the flag to true indicating a fetch is in progress.
|
||||
state.isFetchingThemes = true;
|
||||
|
||||
try {
|
||||
// Fetch themes data.
|
||||
wp.apiFetch( {
|
||||
path: routeNamespace + 'themes/',
|
||||
method: 'GET',
|
||||
cache: 'no-cache',
|
||||
} )
|
||||
.then( ( response ) => {
|
||||
themesData.wpforms = response.wpforms || {};
|
||||
themesData.custom = response.custom || {};
|
||||
|
||||
el.$window.trigger( 'wpformsBuilderThemesDataLoaded' );
|
||||
} )
|
||||
.catch( ( error ) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error( error?.message );
|
||||
} )
|
||||
.finally( () => {
|
||||
state.isFetchingThemes = false;
|
||||
} );
|
||||
} catch ( error ) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error( error );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Save custom themes.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
saveCustomThemes() {
|
||||
// Custom themes do not exist.
|
||||
if ( state.isSavingThemes || ! themesData.custom || ! isAdmin ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the flag to true indicating a saving is in progress.
|
||||
state.isSavingThemes = true;
|
||||
|
||||
try {
|
||||
// Save themes.
|
||||
wp.apiFetch( {
|
||||
path: routeNamespace + 'themes/custom/',
|
||||
method: 'POST',
|
||||
data: { customThemes: themesData.custom },
|
||||
} )
|
||||
.then( ( response ) => {
|
||||
if ( ! response?.result ) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log( response?.error );
|
||||
}
|
||||
} )
|
||||
.catch( ( error ) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error( error?.message );
|
||||
} )
|
||||
.finally( () => {
|
||||
state.isSavingThemes = false;
|
||||
} );
|
||||
} catch ( error ) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error( error );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the current style attributes state.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {Object} settings Settings.
|
||||
*
|
||||
* @return {Array} Current style attributes.
|
||||
*/
|
||||
getCurrentStyleAttributes( settings ) {
|
||||
const defaultAttributes = Object.keys( themesData.wpforms.default?.settings );
|
||||
const currentStyleAttributes = {};
|
||||
|
||||
for ( const key in defaultAttributes ) {
|
||||
const attr = defaultAttributes[ key ];
|
||||
|
||||
currentStyleAttributes[ attr ] = WPFormsBuilderThemes.common.prepareComplexAttrValues( settings[ attr ], attr ) ?? '';
|
||||
}
|
||||
|
||||
return currentStyleAttributes;
|
||||
},
|
||||
|
||||
/**
|
||||
* Maybe create a custom theme.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
*
|
||||
* @return {boolean} Whether the custom theme is created.
|
||||
*/
|
||||
maybeCreateCustomTheme() {
|
||||
const settings = WPFormsBuilderThemes.getSettings();
|
||||
const currentStyles = app.getCurrentStyleAttributes( settings );
|
||||
const isWPFormsTheme = !! themesData.wpforms[ settings.wpformsTheme ];
|
||||
const isCustomTheme = !! themesData.custom[ settings.wpformsTheme ];
|
||||
|
||||
// It is one of the default themes without any changes.
|
||||
if (
|
||||
isWPFormsTheme &&
|
||||
app.getPreparedDefaultThemeSettings( themesData.wpforms[ settings.wpformsTheme ]?.settings ) === JSON.stringify( currentStyles )
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// It is a modified default theme OR unknown custom theme.
|
||||
if ( isWPFormsTheme || ! isCustomTheme ) {
|
||||
app.createCustomTheme( settings, currentStyles );
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepare default theme settings for comparing.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {Object} settings Theme properties.
|
||||
*
|
||||
* @return {string} Whether the custom theme is created.
|
||||
*/
|
||||
getPreparedDefaultThemeSettings( settings ) {
|
||||
const preparedSettings = {};
|
||||
|
||||
Object.keys( settings ).forEach( ( key ) => {
|
||||
preparedSettings[ key ] = WPFormsBuilderThemes.common.removeRgbaSpaces( settings[ key ] );
|
||||
} );
|
||||
|
||||
return JSON.stringify( preparedSettings );
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a custom theme.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {Object} settings Style settings.
|
||||
* @param {Object} currentStyles Current style settings.
|
||||
*
|
||||
* @return {boolean} Whether the custom theme is created.
|
||||
*/
|
||||
createCustomTheme( settings, currentStyles = null ) {
|
||||
let counter = 0;
|
||||
let themeSlug = settings.wpformsTheme;
|
||||
|
||||
const baseTheme = app.getTheme( settings.wpformsTheme ) || themesData.wpforms.default;
|
||||
let themeName = baseTheme.name;
|
||||
|
||||
themesData.custom = themesData.custom || {};
|
||||
|
||||
// Determine the theme slug and the number of copies.
|
||||
do {
|
||||
counter++;
|
||||
themeSlug = themeSlug + '-copy-' + counter;
|
||||
} while ( themesData.custom[ themeSlug ] && counter < 10000 );
|
||||
|
||||
const copyStr = counter < 2 ? strings.theme_copy : strings.theme_copy + ' ' + counter;
|
||||
|
||||
themeName += ' (' + copyStr + ')';
|
||||
|
||||
// Add the new custom theme.
|
||||
themesData.custom[ themeSlug ] = {
|
||||
name: themeName,
|
||||
settings: currentStyles || app.getCurrentStyleAttributes( settings ),
|
||||
};
|
||||
|
||||
app.updateEnabledThemes( themeSlug, themesData.custom[ themeSlug ] );
|
||||
|
||||
// Update the settings with the new custom theme settings.
|
||||
WPFormsBuilderThemes.store.set( 'wpformsTheme', themeSlug );
|
||||
WPFormsBuilderThemes.store.set( 'isCustomTheme', 'true' );
|
||||
WPFormsBuilderThemes.store.set( 'themeName', themeName );
|
||||
|
||||
app.updateThemesList();
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update custom theme.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} attribute Attribute name.
|
||||
* @param {string} value New attribute value.
|
||||
*/
|
||||
updateCustomThemeAttribute( attribute, value ) {
|
||||
const settings = WPFormsBuilderThemes.getSettings();
|
||||
const themeSlug = settings.wpformsTheme;
|
||||
|
||||
// Skip if it is one of the WPForms themes OR the attribute is not in the theme settings.
|
||||
if (
|
||||
themesData.wpforms[ themeSlug ] ||
|
||||
(
|
||||
attribute !== 'themeName' &&
|
||||
! themesData.wpforms.default.settings[ attribute ]
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip if the custom theme doesn't exist in some rare cases.
|
||||
if ( ! themesData.custom[ themeSlug ] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the theme data.
|
||||
if ( attribute === 'themeName' ) {
|
||||
themesData.custom[ themeSlug ].name = value;
|
||||
} else {
|
||||
themesData.custom[ themeSlug ].settings = themesData.custom[ themeSlug ].settings || themesData.wpforms.default.settings;
|
||||
themesData.custom[ themeSlug ].settings[ attribute ] = value;
|
||||
|
||||
app.maybeUpdateColorIndicator( attribute, value );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Maybe update the custom theme settings.
|
||||
*
|
||||
* @param {string} key Setting key.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
maybeUpdateCustomTheme( key ) {
|
||||
const settings = WPFormsBuilderThemes.getSettings();
|
||||
const isCustomTheme = settings.isCustomTheme === 'true';
|
||||
|
||||
if ( ! isCustomTheme ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const attrValue = WPFormsBuilderThemes.common.prepareComplexAttrValues( settings[ key ], key );
|
||||
|
||||
app.updateCustomThemeAttribute( key, attrValue );
|
||||
},
|
||||
|
||||
/**
|
||||
* Maybe update the color indicators for the custom theme.
|
||||
*
|
||||
* @param {string} settingKey Setting key.
|
||||
* @param {string} settingValue Setting value.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
maybeUpdateColorIndicator( settingKey, settingValue ) {
|
||||
const colorSettingKeys = [ 'buttonBackgroundColor', 'buttonTextColor', 'labelColor', 'labelSublabelColor', 'fieldBorderColor' ];
|
||||
|
||||
if ( ! colorSettingKeys.includes( settingKey ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $indicators = el.$themesControl.find( 'button.is-active .wpforms-builder-themes-indicators' );
|
||||
const indicatorIndex = colorSettingKeys.indexOf( settingKey );
|
||||
const $indicator = $indicators.find( `.component-color-indicator[data-index="${ indicatorIndex }"]` );
|
||||
|
||||
if ( $indicator.length ) {
|
||||
$indicator.css( 'background-color', settingValue );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Maybe display upgrades modal in Lite.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} themeSlug The theme slug.
|
||||
*
|
||||
* @return {boolean} True if modal was displayed.
|
||||
*/
|
||||
maybeDisplayUpgradeModal( themeSlug ) {
|
||||
if ( ! app.isDisabledTheme( themeSlug ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isPro ) {
|
||||
WPFormsBuilderThemes.common.showProModal( 'themes', strings.pro_sections.themes );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ! isLicenseActive ) {
|
||||
WPFormsBuilderThemes.common.showLicenseModal( 'themes', strings.pro_sections.themes, 'select-theme' );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Change theme name event handler.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {string} value New attribute value.
|
||||
*/
|
||||
changeThemeName( value ) {
|
||||
app.updateCustomThemeAttribute( 'themeName', value );
|
||||
},
|
||||
|
||||
/**
|
||||
* Delete theme event handler.
|
||||
*
|
||||
* @param {string} deleteThemeSlug Theme slug.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*/
|
||||
deleteTheme( deleteThemeSlug ) {
|
||||
// Remove theme from the theme storage.
|
||||
delete themesData.custom[ deleteThemeSlug ];
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the theme delete the confirmation modal window.
|
||||
*
|
||||
* @since 1.9.7
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
*/
|
||||
deleteThemeModal( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
const settings = WPFormsBuilderThemes.getSettings();
|
||||
const selectedThemeSlug = settings.wpformsTheme;
|
||||
const selectedThemeName = app.getTheme( selectedThemeSlug )?.name;
|
||||
const confirm = strings.theme_delete_confirm.replace( '%1$s', `<b>${ _.escape( selectedThemeName ) }</b>` );
|
||||
const content = `<p class="wpforms-theme-delete-text">${ confirm } ${ strings.theme_delete_cant_undone }</p>`;
|
||||
|
||||
$.confirm( {
|
||||
title: strings.theme_delete_title,
|
||||
content,
|
||||
icon: 'wpforms-exclamation-circle',
|
||||
type: 'red wpforms-builder-themes-modal',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: strings.theme_delete_yes,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action() {
|
||||
// Delete the theme and switch to the default theme.
|
||||
app.deleteTheme( selectedThemeSlug );
|
||||
app.selectTheme( 'default' );
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: strings.cancel,
|
||||
keys: [ 'esc' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
};
|
||||
|
||||
return app;
|
||||
}
|
||||
Vendored
Executable
+15
File diff suppressed because one or more lines are too long
+282
@@ -0,0 +1,282 @@
|
||||
/* global wpforms_builder, Choices, wpf */
|
||||
|
||||
/**
|
||||
* @param wpforms_builder.no_pages_found
|
||||
*/
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
/**
|
||||
* WPForms ChoicesJS utility methods for the Admin Builder.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*/
|
||||
var WPForms = window.WPForms || {}; // eslint-disable-line no-var
|
||||
|
||||
WPForms.Admin = WPForms.Admin || {};
|
||||
WPForms.Admin.Builder = WPForms.Admin.Builder || {};
|
||||
|
||||
WPForms.Admin.Builder.WPFormsChoicesJS = WPForms.Admin.Builder.WPFormsChoicesJS || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Set up the Select Page ChoicesJS instance.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @param {Object} element DOM Element where to init ChoicesJS.
|
||||
* @param {Object} choicesJSArgs ChoicesJS init options.
|
||||
* @param {Object} ajaxArgs Object containing `action` and `nonce` to perform AJAX search.
|
||||
*
|
||||
* @return {Choices} ChoicesJS instance.
|
||||
*/
|
||||
setup( element, choicesJSArgs, ajaxArgs ) {
|
||||
let $element = $( element );
|
||||
let choicesJS = $element.data( 'choicesjs' );
|
||||
|
||||
// Destroy existing choicesJS instance.
|
||||
if ( choicesJS ) {
|
||||
choicesJS.destroy();
|
||||
}
|
||||
|
||||
// Remove choicesJS elements from the DOM for cloned instances.
|
||||
if ( $element.hasClass( 'choices__input' ) ) {
|
||||
const $choices = $element.closest( '.choices' );
|
||||
const $select = $element.detach()
|
||||
.removeClass( 'choices__input' )
|
||||
.data( 'choice', null )
|
||||
.attr( 'data-choice', null );
|
||||
|
||||
$choices.replaceWith( $select );
|
||||
$element = $choices.prevObject;
|
||||
element = $element[ 0 ];
|
||||
}
|
||||
|
||||
choicesJSArgs.searchEnabled = true;
|
||||
choicesJSArgs.allowHTML = false; // TODO: Remove after next Choices.js release.
|
||||
choicesJSArgs.searchChoices = ajaxArgs.nonce === null; // Enable searchChoices when not using AJAX.
|
||||
choicesJSArgs.renderChoiceLimit = -1;
|
||||
choicesJSArgs.noChoicesText = choicesJSArgs.noChoicesText || wpforms_builder.no_pages_found;
|
||||
choicesJSArgs.noResultsText = choicesJSArgs.noResultsText || wpforms_builder.no_pages_found;
|
||||
|
||||
choicesJS = new Choices( element, choicesJSArgs );
|
||||
|
||||
if ( ajaxArgs.nonce === null ) {
|
||||
return choicesJS;
|
||||
}
|
||||
|
||||
$element.data( 'choicesjs', choicesJS );
|
||||
app.setupEvents( $element, choicesJS, ajaxArgs );
|
||||
|
||||
return choicesJS;
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup ChoicesJS events.
|
||||
*
|
||||
* @since 1.9.8.3
|
||||
*
|
||||
* @param {Object} $element jQuery element where to init ChoicesJS.
|
||||
* @param {Object} choicesJS ChoicesJS instance.
|
||||
* @param {Object} ajaxArgs Object containing `action` and `nonce` to perform AJAX search.
|
||||
*/
|
||||
setupEvents( $element, choicesJS, ajaxArgs ) {
|
||||
const containerOuter = choicesJS.containerOuter?.element || $element.closest( '.choices' )[ 0 ];
|
||||
|
||||
app.setupSearchEvents( $element, choicesJS, ajaxArgs );
|
||||
|
||||
choicesJS.passedElement.element.addEventListener( 'change', function() {
|
||||
const select = $( this ),
|
||||
isMultiple = select.prop( 'multiple' );
|
||||
|
||||
if ( ! isMultiple ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fieldId = select.data( 'field-id' ),
|
||||
fieldName = select.data( 'field-name' ),
|
||||
value = choicesJS.getValue();
|
||||
|
||||
const selected = value.map( function( item ) {
|
||||
return item.value;
|
||||
} );
|
||||
|
||||
const $hidden = $( `#wpforms-field-${ fieldId }-${ fieldName }-select-multiple-options` );
|
||||
|
||||
$hidden.val( JSON.stringify( selected ) );
|
||||
} );
|
||||
|
||||
// Add the ability to close the drop-down menu.
|
||||
containerOuter?.addEventListener( 'click', function() {
|
||||
if ( $( this ).hasClass( 'is-open' ) ) {
|
||||
choicesJS.hideDropdown();
|
||||
}
|
||||
} );
|
||||
|
||||
// Show more button for choices after the group is toggled.
|
||||
$( document )
|
||||
.on( 'wpformsFieldOptionGroupToggled', function() {
|
||||
wpf.showMoreButtonForChoices( containerOuter );
|
||||
} )
|
||||
.on( 'wpformsBeforeFieldDuplicate', function( event, id ) {
|
||||
if ( $element.data( 'field-id' ) !== id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const choices = choicesJS.getValue( true );
|
||||
|
||||
$element.data( 'choicesjs' ).destroy();
|
||||
|
||||
$element.find( 'option' ).each( function( index, option ) {
|
||||
if ( choices.includes( $( option ).val() ) ) {
|
||||
$( option ).prop( 'selected', true );
|
||||
}
|
||||
} );
|
||||
} )
|
||||
.on( 'wpformsFieldDuplicated', function( event, id ) {
|
||||
if ( $element.data( 'field-id' ) !== id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$element.data( 'choicesjs' ).init();
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup ChoicesJS search events.
|
||||
*
|
||||
* @since 1.9.8.3
|
||||
*
|
||||
* @param {Object} $element jQuery element where to init ChoicesJS.
|
||||
* @param {Object} choicesJS ChoicesJS instance.
|
||||
* @param {Object} ajaxArgs Object containing `action` and `nonce` to perform AJAX search.
|
||||
*/
|
||||
setupSearchEvents( $element, choicesJS, ajaxArgs ) {
|
||||
const searchInput = choicesJS.input?.element || $element.nextAll( '.choices__input ' )[ 0 ];
|
||||
|
||||
/*
|
||||
* ChoicesJS doesn't handle empty string search with it's `search` event handler,
|
||||
* so we work around it by detecting empty string search with the ` keyup ` event.
|
||||
*/
|
||||
searchInput?.addEventListener( 'keyup', function( ev ) {
|
||||
// Only capture backspace and delete keypress that results to empty string.
|
||||
if (
|
||||
( ev.which !== 8 && ev.which !== 46 ) ||
|
||||
ev.target.value.length > 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
app.performSearch( choicesJS, '', ajaxArgs );
|
||||
} );
|
||||
|
||||
choicesJS.passedElement?.element.addEventListener( 'search', _.debounce( function( ev ) {
|
||||
// Make sure that the search term is actually changed.
|
||||
if ( choicesJS.input.element.value.length === 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
app.performSearch( choicesJS, ev.detail.value, ajaxArgs );
|
||||
}, 800 ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* Perform search in ChoicesJS instance.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @param {Choices} choicesJS ChoicesJS instance.
|
||||
* @param {string} searchTerm Search term.
|
||||
* @param {Object} ajaxArgs Object containing `action` and `nonce` to perform AJAX search.
|
||||
*/
|
||||
performSearch( choicesJS, searchTerm, ajaxArgs ) {
|
||||
if ( ! ajaxArgs.action || ! ajaxArgs.nonce ) {
|
||||
return;
|
||||
}
|
||||
|
||||
app.displayLoading( choicesJS );
|
||||
|
||||
const requestSearchChoices = app.ajaxSearch( ajaxArgs.action, searchTerm, ajaxArgs.nonce, choicesJS.getValue( true ) );
|
||||
|
||||
requestSearchChoices.done( function( response ) {
|
||||
choicesJS.setChoices( response.data, 'value', 'label', true );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Display "Loading" in the ChoicesJS instance.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*
|
||||
* @param {Choices} choicesJS ChoicesJS instance.
|
||||
*/
|
||||
displayLoading( choicesJS ) {
|
||||
choicesJS.setChoices(
|
||||
[
|
||||
{ value: '', label: `${ wpforms_builder.loading }...`, disabled: true },
|
||||
],
|
||||
'value',
|
||||
'label',
|
||||
true
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Perform AJAX search request.
|
||||
*
|
||||
* @since 1.7.9
|
||||
* @deprecated 1.9.4 Use `ajaxSearch` instead.
|
||||
*
|
||||
* @param {string} action Action to be used when doing ajax request for search.
|
||||
* @param {string} searchTerm Search term.
|
||||
* @param {string} nonce Nonce to be used when doing ajax request.
|
||||
*
|
||||
* @return {Promise} jQuery ajax call promise.
|
||||
*/
|
||||
ajaxSearchPages( action, searchTerm, nonce ) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn( 'WPForms.Admin.Builder.WPFormsChoicesJS.ajaxSearchPages is deprecated. Use WPForms.Admin.Builder.WPFormsChoicesJS.ajaxSearch instead.' );
|
||||
|
||||
return app.ajaxSearch( action, searchTerm, nonce );
|
||||
},
|
||||
|
||||
/**
|
||||
* Perform AJAX search request.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*
|
||||
* @param {string} action Action to be used when doing ajax request for search.
|
||||
* @param {string} searchTerm Search term.
|
||||
* @param {string} nonce Nonce to be used when doing ajax request.
|
||||
* @param {Array} exclude Array of values to exclude from search results.
|
||||
*
|
||||
* @return {Promise} jQuery ajax call promise.
|
||||
*/
|
||||
ajaxSearch( action, searchTerm, nonce, exclude = [] ) {
|
||||
const args = {
|
||||
action,
|
||||
search: searchTerm,
|
||||
_wpnonce: nonce,
|
||||
exclude,
|
||||
};
|
||||
|
||||
return $.get(
|
||||
wpforms_builder.ajax_url,
|
||||
args
|
||||
).fail(
|
||||
function( err ) {
|
||||
console.error( err ); // eslint-disable-line no-console
|
||||
}
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
Vendored
Executable
+1
@@ -0,0 +1 @@
|
||||
var WPForms=window.WPForms||{};WPForms.Admin=WPForms.Admin||{},WPForms.Admin.Builder=WPForms.Admin.Builder||{},WPForms.Admin.Builder.WPFormsChoicesJS=WPForms.Admin.Builder.WPFormsChoicesJS||((o,r)=>{let c={setup(e,n,o){let i=r(e),a=i.data("choicesjs");var t,s;return a&&a.destroy(),i.hasClass("choices__input")&&(t=i.closest(".choices"),s=i.detach().removeClass("choices__input").data("choice",null).attr("data-choice",null),t.replaceWith(s),e=(i=t.prevObject)[0]),n.searchEnabled=!0,n.allowHTML=!1,n.searchChoices=null===o.nonce,n.renderChoiceLimit=-1,n.noChoicesText=n.noChoicesText||wpforms_builder.no_pages_found,n.noResultsText=n.noResultsText||wpforms_builder.no_pages_found,a=new Choices(e,n),null!==o.nonce&&(i.data("choicesjs",a),c.setupEvents(i,a,o)),a},setupEvents(i,a,e){let n=a.containerOuter?.element||i.closest(".choices")[0];c.setupSearchEvents(i,a,e),a.passedElement.element.addEventListener("change",function(){var e,n,o=r(this);o.prop("multiple")&&(e=o.data("field-id"),o=o.data("field-name"),n=a.getValue().map(function(e){return e.value}),r(`#wpforms-field-${e}-${o}-select-multiple-options`).val(JSON.stringify(n)))}),n?.addEventListener("click",function(){r(this).hasClass("is-open")&&a.hideDropdown()}),r(o).on("wpformsFieldOptionGroupToggled",function(){wpf.showMoreButtonForChoices(n)}).on("wpformsBeforeFieldDuplicate",function(e,n){if(i.data("field-id")===n){let o=a.getValue(!0);i.data("choicesjs").destroy(),i.find("option").each(function(e,n){o.includes(r(n).val())&&r(n).prop("selected",!0)})}}).on("wpformsFieldDuplicated",function(e,n){i.data("field-id")===n&&i.data("choicesjs").init()})},setupSearchEvents(e,n,o){(n.input?.element||e.nextAll(".choices__input ")[0])?.addEventListener("keyup",function(e){8!==e.which&&46!==e.which||0<e.target.value.length||c.performSearch(n,"",o)}),n.passedElement?.element.addEventListener("search",_.debounce(function(e){0!==n.input.element.value.length&&c.performSearch(n,e.detail.value,o)},800))},performSearch(n,e,o){o.action&&o.nonce&&(c.displayLoading(n),c.ajaxSearch(o.action,e,o.nonce,n.getValue(!0)).done(function(e){n.setChoices(e.data,"value","label",!0)}))},displayLoading(e){e.setChoices([{value:"",label:wpforms_builder.loading+"...",disabled:!0}],"value","label",!0)},ajaxSearchPages(e,n,o){return console.warn("WPForms.Admin.Builder.WPFormsChoicesJS.ajaxSearchPages is deprecated. Use WPForms.Admin.Builder.WPFormsChoicesJS.ajaxSearch instead."),c.ajaxSearch(e,n,o)},ajaxSearch(e,n,o,i=[]){return r.get(wpforms_builder.ajax_url,{action:e,search:n,_wpnonce:o,exclude:i}).fail(function(e){console.error(e)})}};return c})(document,(window,jQuery));
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
/* global wpforms_challenge_admin, ajaxurl, WPFormsBuilder */
|
||||
/**
|
||||
* WPForms Challenge Admin function.
|
||||
*
|
||||
* @since 1.5.0
|
||||
* @since 1.6.2 Challenge v2
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var WPFormsChallenge = window.WPFormsChallenge || {};
|
||||
|
||||
WPFormsChallenge.admin = window.WPFormsChallenge.admin || ( function( document, window, $ ) {
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var app = {
|
||||
|
||||
l10n: wpforms_challenge_admin,
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
init: function() {
|
||||
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
ready: function() {
|
||||
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Register JS events.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
events: function() {
|
||||
|
||||
$( '.wpforms-challenge-list-block' )
|
||||
.on( 'click', '.challenge-skip', app.skipChallenge )
|
||||
.on( 'click', '.challenge-cancel', app.cancelChallenge )
|
||||
.on( 'click', '.toggle-list', app.toggleList );
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle list icon click.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param {object} e Event object.
|
||||
*/
|
||||
toggleList: function( e ) {
|
||||
|
||||
var $icon = $( e.target ),
|
||||
$listBlock = $( '.wpforms-challenge-list-block' );
|
||||
|
||||
if ( ! $listBlock.length || ! $icon.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $listBlock.hasClass( 'closed' ) ) {
|
||||
wpforms_challenge_admin.option.window_closed = '0';
|
||||
$listBlock.removeClass( 'closed' );
|
||||
|
||||
setTimeout( function() {
|
||||
$listBlock.removeClass( 'transition-back' );
|
||||
}, 600 );
|
||||
} else {
|
||||
wpforms_challenge_admin.option.window_closed = '1';
|
||||
$listBlock.addClass( 'closed' );
|
||||
|
||||
// Add `transition-back` class when the forward transition is completed.
|
||||
// It is needed to properly implement transitions order for some elements.
|
||||
setTimeout( function() {
|
||||
$listBlock.addClass( 'transition-back' );
|
||||
}, 600 );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Skip the Challenge without starting it.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
skipChallenge: function() {
|
||||
|
||||
var optionData = {
|
||||
status : 'skipped',
|
||||
seconds_spent: 0,
|
||||
seconds_left : app.l10n.minutes_left * 60,
|
||||
};
|
||||
|
||||
$( '.wpforms-challenge' ).remove();
|
||||
|
||||
// In the Form Builder, we must also make the Embed button clickable.
|
||||
$( '#wpforms-embed' ).removeClass( 'wpforms-disabled' );
|
||||
|
||||
app.saveChallengeOption( optionData );
|
||||
},
|
||||
|
||||
/**
|
||||
* Cancel Challenge after starting it.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
cancelChallenge: function() {
|
||||
|
||||
var core = WPFormsChallenge.core;
|
||||
|
||||
core.timer.pause();
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
var optionData = {
|
||||
status : 'canceled',
|
||||
seconds_spent: core.timer.getSecondsSpent(),
|
||||
seconds_left : core.timer.getSecondsLeft(),
|
||||
feedback_sent: false,
|
||||
};
|
||||
/* eslint-enable */
|
||||
|
||||
core.removeChallengeUI();
|
||||
core.clearLocalStorage();
|
||||
|
||||
if ( typeof WPFormsBuilder !== 'undefined' ) {
|
||||
WPFormsChallenge.admin.saveChallengeOption( optionData )
|
||||
.done( function() { // Save the form before removing scripts if we're in a WPForms Builder.
|
||||
if ( localStorage.getItem( 'wpformsChallengeStep' ) !== null ) {
|
||||
WPFormsBuilder.formSave( false );
|
||||
}
|
||||
} ).done( // Remove scripts related to challenge.
|
||||
$( '#wpforms-challenge-admin-js, #wpforms-challenge-core-js, #wpforms-challenge-admin-js-extra, #wpforms-challenge-builder-js' )
|
||||
.remove()
|
||||
);
|
||||
} else {
|
||||
WPFormsChallenge.admin.saveChallengeOption( optionData )
|
||||
.done( app.triggerPageSave ); // Assume we're on form embed page.
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set Challenge parameter(s) to Challenge option.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param {object} optionData Query using option schema keys.
|
||||
*
|
||||
* @returns {promise} jQuery.post() promise interface.
|
||||
*/
|
||||
saveChallengeOption: function( optionData ) {
|
||||
|
||||
var data = {
|
||||
action : 'wpforms_challenge_save_option',
|
||||
option_data: optionData,
|
||||
_wpnonce : app.l10n.nonce,
|
||||
};
|
||||
|
||||
// Save window closed (collapsed) state as well.
|
||||
data.option_data.window_closed = wpforms_challenge_admin.option.window_closed;
|
||||
|
||||
$.extend( wpforms_challenge_admin.option, optionData );
|
||||
|
||||
return $.post( ajaxurl, data, function( response ) {
|
||||
if ( ! response.success ) {
|
||||
console.error( 'Error saving WPForms Challenge option.' );
|
||||
}
|
||||
} );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
WPFormsChallenge.admin.init();
|
||||
Vendored
Executable
+1
@@ -0,0 +1 @@
|
||||
var WPFormsChallenge=window.WPFormsChallenge||{};WPFormsChallenge.admin=window.WPFormsChallenge.admin||(l=>{var o={l10n:wpforms_challenge_admin,init:function(){l(o.ready)},ready:function(){o.events()},events:function(){l(".wpforms-challenge-list-block").on("click",".challenge-skip",o.skipChallenge).on("click",".challenge-cancel",o.cancelChallenge).on("click",".toggle-list",o.toggleList)},toggleList:function(e){var e=l(e.target),n=l(".wpforms-challenge-list-block");n.length&&e.length&&(n.hasClass("closed")?(wpforms_challenge_admin.option.window_closed="0",n.removeClass("closed"),setTimeout(function(){n.removeClass("transition-back")},600)):(wpforms_challenge_admin.option.window_closed="1",n.addClass("closed"),setTimeout(function(){n.addClass("transition-back")},600)))},skipChallenge:function(){var e={status:"skipped",seconds_spent:0,seconds_left:60*o.l10n.minutes_left};l(".wpforms-challenge").remove(),l("#wpforms-embed").removeClass("wpforms-disabled"),o.saveChallengeOption(e)},cancelChallenge:function(){var e=WPFormsChallenge.core,n=(e.timer.pause(),{status:"canceled",seconds_spent:e.timer.getSecondsSpent(),seconds_left:e.timer.getSecondsLeft(),feedback_sent:!1});e.removeChallengeUI(),e.clearLocalStorage(),"undefined"!=typeof WPFormsBuilder?WPFormsChallenge.admin.saveChallengeOption(n).done(function(){null!==localStorage.getItem("wpformsChallengeStep")&&WPFormsBuilder.formSave(!1)}).done(l("#wpforms-challenge-admin-js, #wpforms-challenge-core-js, #wpforms-challenge-admin-js-extra, #wpforms-challenge-builder-js").remove()):WPFormsChallenge.admin.saveChallengeOption(n).done(o.triggerPageSave)},saveChallengeOption:function(e){var n={action:"wpforms_challenge_save_option",option_data:e,_wpnonce:o.l10n.nonce};return n.option_data.window_closed=wpforms_challenge_admin.option.window_closed,l.extend(wpforms_challenge_admin.option,e),l.post(ajaxurl,n,function(e){e.success||console.error("Error saving WPForms Challenge option.")})}};return o})((document,window,jQuery)),WPFormsChallenge.admin.init();
|
||||
+294
@@ -0,0 +1,294 @@
|
||||
/* global WPForms, WPFormsBuilder, wpforms_challenge_admin, WPFormsFormEmbedWizard */
|
||||
/**
|
||||
* WPForms Challenge function.
|
||||
*
|
||||
* @since 1.5.0
|
||||
* @since 1.6.2 Challenge v2
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var WPFormsChallenge = window.WPFormsChallenge || {};
|
||||
|
||||
WPFormsChallenge.builder = window.WPFormsChallenge.builder || ( function( document, window, $ ) {
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
init: function() {
|
||||
|
||||
$( app.ready );
|
||||
$( window ).on( 'load', function() {
|
||||
|
||||
// in case of jQuery 3.+ we need to wait for an `ready` event first.
|
||||
if ( typeof $.ready.then === 'function' ) {
|
||||
$.ready.then( app.load );
|
||||
} else {
|
||||
app.load();
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
ready: function() {
|
||||
|
||||
app.setup();
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Window load.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
load: function() {
|
||||
|
||||
if ( [ 'started', 'paused' ].indexOf( wpforms_challenge_admin.option.status ) > -1 ) {
|
||||
WPFormsChallenge.core.updateTooltipUI();
|
||||
}
|
||||
|
||||
$( '.wpforms-challenge' ).show();
|
||||
},
|
||||
|
||||
/**
|
||||
* Initial setup.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
setup: function() {
|
||||
if ( wpforms_challenge_admin.option.status === 'inited' ) {
|
||||
WPFormsChallenge.core.clearLocalStorage();
|
||||
app.showWelcomePopup();
|
||||
}
|
||||
|
||||
app.initTooltips();
|
||||
|
||||
$( '#wpforms-embed' ).addClass( 'wpforms-disabled' );
|
||||
|
||||
$( document ).on( 'wpformsWizardPopupClose', app.enableEmbed );
|
||||
},
|
||||
|
||||
/**
|
||||
* Register JS events.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
events: function() {
|
||||
|
||||
// Start the Challenge.
|
||||
$( '#wpforms-challenge-welcome-builder-popup' ).on( 'click', 'button', app.startChallenge );
|
||||
|
||||
// Step 1.
|
||||
$( '.wpforms-challenge-step1-done' ).on( 'click', function() {
|
||||
WPFormsChallenge.core.stepCompleted( 1 );
|
||||
} );
|
||||
|
||||
$( '#wpforms-builder' )
|
||||
|
||||
// Register select template event when the setup panel is ready.
|
||||
.on( 'wpformsBuilderSetupReady', function() {
|
||||
app.eventSelectTemplate();
|
||||
} )
|
||||
|
||||
// Restore tooltips when switching builder panels/sections.
|
||||
.on( 'wpformsPanelSwitch wpformsPanelSectionSwitch wpformsBuilderPanelLoaded', function() {
|
||||
WPFormsChallenge.core.updateTooltipUI();
|
||||
} );
|
||||
|
||||
// Step 3 - Add fields.
|
||||
$( '.wpforms-challenge-step3-done' ).on( 'click', app.gotoNotificationStep );
|
||||
|
||||
// Step 4 - Notifications.
|
||||
$( document ).on( 'click', '.wpforms-challenge-step4-done', app.showEmbedPopup );
|
||||
|
||||
// Step 5 - Reinit Embed popup.
|
||||
$( document ).on( 'wpformsChallengeCoreBeforeRefreshPage', function( event, originalClickEvent ) {
|
||||
if ( $( originalClickEvent.currentTarget ).hasClass( 'wpforms-challenge-step5-item' ) ) {
|
||||
event.preventDefault();
|
||||
app.showEmbedPopup();
|
||||
}
|
||||
} );
|
||||
|
||||
// Tooltipster ready.
|
||||
$.tooltipster.on( 'ready', app.tooltipsterReady );
|
||||
|
||||
// Move to step 3 if challenge is forced and exisiting form is opened.
|
||||
$( document ).on( 'wpformsBuilderReady', function() {
|
||||
if ( $( '.wpforms-panel-fields-button' ).hasClass( 'active' ) && WPFormsChallenge.core.loadStep() <= 2 ) {
|
||||
WPFormsChallenge.core.stepCompleted( 1 );
|
||||
WPFormsChallenge.core.stepCompleted( 2 );
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize tooltips.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
initTooltips() {
|
||||
const tooltipAnchors = [
|
||||
'#wpforms-setup-name',
|
||||
'.wpforms-setup-title .wpforms-setup-title-after',
|
||||
'#add-fields a i',
|
||||
'#wpforms-builder-settings-notifications-title',
|
||||
];
|
||||
|
||||
$.each( tooltipAnchors, function( i, anchor ) {
|
||||
WPFormsChallenge.core.initTooltips( i + 1, anchor, null );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Register select template event.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*/
|
||||
eventSelectTemplate: function() {
|
||||
|
||||
$( '#wpforms-panel-setup' )
|
||||
|
||||
// Step 2 - Select the Form template.
|
||||
.off( 'click', '.wpforms-template-select' ) // Intercept Form Builder's form template selection and apply own logic.
|
||||
.on( 'click', '.wpforms-template-select', function( e ) {
|
||||
app.builderTemplateSelect( this, e );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Start the Challenge.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
startChallenge: function() {
|
||||
|
||||
WPFormsChallenge.admin.saveChallengeOption( { status: 'started' } );
|
||||
WPFormsChallenge.core.initListUI( 'started' );
|
||||
$( '.wpforms-challenge-popup-container' ).fadeOut( function() {
|
||||
$( '#wpforms-challenge-welcome-builder-popup' ).hide();
|
||||
} );
|
||||
WPFormsChallenge.core.timer.run( WPFormsChallenge.core.timer.initialSecondsLeft );
|
||||
WPFormsChallenge.core.updateTooltipUI();
|
||||
},
|
||||
|
||||
/**
|
||||
* Go to Step.
|
||||
*
|
||||
* @since 1.6.2
|
||||
* @since 1.7.5 Deprecated.
|
||||
*
|
||||
* @param {number|string} step Last saved step.
|
||||
*/
|
||||
gotoStep: function( step ) {
|
||||
console.warn( 'WARNING! Function "WPFormsChallenge.builder.gotoStep()" has been deprecated.' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Save the second step before a template is selected.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param {string} el Element selector.
|
||||
* @param {object} e Event.
|
||||
*/
|
||||
builderTemplateSelect: function( el, e ) {
|
||||
|
||||
WPFormsChallenge.core.resumeChallengeAndExec( e, function() {
|
||||
|
||||
WPFormsChallenge.core.stepCompleted( 2 )
|
||||
.done( WPForms.Admin.Builder.Setup.selectTemplate.bind( el, e ) );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Tooltipster ready event callback.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*
|
||||
* @param {object} e Event object.
|
||||
*/
|
||||
tooltipsterReady: function( e ) {
|
||||
|
||||
var step = $( e.origin ).data( 'wpforms-challenge-step' );
|
||||
var formId = $( '#wpforms-builder-form' ).data( 'id' );
|
||||
|
||||
step = parseInt( step, 10 ) || 0;
|
||||
formId = parseInt( formId, 10 ) || 0;
|
||||
|
||||
// Save challenge form ID right after it's created.
|
||||
if ( 3 === step && formId > 0 ) {
|
||||
WPFormsChallenge.admin.saveChallengeOption( { form_id: formId } ); // eslint-disable-line camelcase
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Display 'Welcome to the Form Builder' popup.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
showWelcomePopup: function() {
|
||||
|
||||
$( '#wpforms-challenge-welcome-builder-popup' ).show();
|
||||
$( '.wpforms-challenge-popup-container' ).fadeIn();
|
||||
},
|
||||
|
||||
/**
|
||||
* Go to Notification step.
|
||||
*
|
||||
* @since 1.7.5
|
||||
*
|
||||
* @param {object} e Event object.
|
||||
*/
|
||||
gotoNotificationStep: function( e ) {
|
||||
|
||||
WPFormsChallenge.core.stepCompleted( 3 ).done( function() {
|
||||
|
||||
WPFormsBuilder.panelSwitch( 'settings' );
|
||||
WPFormsBuilder.panelSectionSwitch( $( '.wpforms-panel .wpforms-panel-sidebar-section-notifications' ) );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Display 'Embed in a Page' popup.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
showEmbedPopup: function() {
|
||||
|
||||
WPFormsChallenge.core.stepCompleted( 4 ).done(
|
||||
WPFormsFormEmbedWizard.openPopup
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Enable Embed button when Embed popup is closed.
|
||||
*
|
||||
* @since 1.7.4
|
||||
*/
|
||||
enableEmbed: function() {
|
||||
|
||||
$( '#wpforms-embed' ).removeClass( 'wpforms-disabled' );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPFormsChallenge.builder.init();
|
||||
Vendored
Executable
+1
@@ -0,0 +1 @@
|
||||
var WPFormsChallenge=window.WPFormsChallenge||{};WPFormsChallenge.builder=window.WPFormsChallenge.builder||((e,o,n)=>{var t={init:function(){n(t.ready),n(o).on("load",function(){"function"==typeof n.ready.then?n.ready.then(t.load):t.load()})},ready:function(){t.setup(),t.events()},load:function(){-1<["started","paused"].indexOf(wpforms_challenge_admin.option.status)&&WPFormsChallenge.core.updateTooltipUI(),n(".wpforms-challenge").show()},setup:function(){"inited"===wpforms_challenge_admin.option.status&&(WPFormsChallenge.core.clearLocalStorage(),t.showWelcomePopup()),t.initTooltips(),n("#wpforms-embed").addClass("wpforms-disabled"),n(e).on("wpformsWizardPopupClose",t.enableEmbed)},events:function(){n("#wpforms-challenge-welcome-builder-popup").on("click","button",t.startChallenge),n(".wpforms-challenge-step1-done").on("click",function(){WPFormsChallenge.core.stepCompleted(1)}),n("#wpforms-builder").on("wpformsBuilderSetupReady",function(){t.eventSelectTemplate()}).on("wpformsPanelSwitch wpformsPanelSectionSwitch wpformsBuilderPanelLoaded",function(){WPFormsChallenge.core.updateTooltipUI()}),n(".wpforms-challenge-step3-done").on("click",t.gotoNotificationStep),n(e).on("click",".wpforms-challenge-step4-done",t.showEmbedPopup),n(e).on("wpformsChallengeCoreBeforeRefreshPage",function(e,o){n(o.currentTarget).hasClass("wpforms-challenge-step5-item")&&(e.preventDefault(),t.showEmbedPopup())}),n.tooltipster.on("ready",t.tooltipsterReady),n(e).on("wpformsBuilderReady",function(){n(".wpforms-panel-fields-button").hasClass("active")&&WPFormsChallenge.core.loadStep()<=2&&(WPFormsChallenge.core.stepCompleted(1),WPFormsChallenge.core.stepCompleted(2))})},initTooltips(){n.each(["#wpforms-setup-name",".wpforms-setup-title .wpforms-setup-title-after","#add-fields a i","#wpforms-builder-settings-notifications-title"],function(e,o){WPFormsChallenge.core.initTooltips(e+1,o,null)})},eventSelectTemplate:function(){n("#wpforms-panel-setup").off("click",".wpforms-template-select").on("click",".wpforms-template-select",function(e){t.builderTemplateSelect(this,e)})},startChallenge:function(){WPFormsChallenge.admin.saveChallengeOption({status:"started"}),WPFormsChallenge.core.initListUI("started"),n(".wpforms-challenge-popup-container").fadeOut(function(){n("#wpforms-challenge-welcome-builder-popup").hide()}),WPFormsChallenge.core.timer.run(WPFormsChallenge.core.timer.initialSecondsLeft),WPFormsChallenge.core.updateTooltipUI()},gotoStep:function(e){console.warn('WARNING! Function "WPFormsChallenge.builder.gotoStep()" has been deprecated.')},builderTemplateSelect:function(e,o){WPFormsChallenge.core.resumeChallengeAndExec(o,function(){WPFormsChallenge.core.stepCompleted(2).done(WPForms.Admin.Builder.Setup.selectTemplate.bind(e,o))})},tooltipsterReady:function(e){var e=n(e.origin).data("wpforms-challenge-step"),o=n("#wpforms-builder-form").data("id"),e=parseInt(e,10)||0,o=parseInt(o,10)||0;3===e&&0<o&&WPFormsChallenge.admin.saveChallengeOption({form_id:o})},showWelcomePopup:function(){n("#wpforms-challenge-welcome-builder-popup").show(),n(".wpforms-challenge-popup-container").fadeIn()},gotoNotificationStep:function(e){WPFormsChallenge.core.stepCompleted(3).done(function(){WPFormsBuilder.panelSwitch("settings"),WPFormsBuilder.panelSectionSwitch(n(".wpforms-panel .wpforms-panel-sidebar-section-notifications"))})},showEmbedPopup:function(){WPFormsChallenge.core.stepCompleted(4).done(WPFormsFormEmbedWizard.openPopup)},enableEmbed:function(){n("#wpforms-embed").removeClass("wpforms-disabled")}};return t})(document,window,jQuery),WPFormsChallenge.builder.init();
|
||||
+927
@@ -0,0 +1,927 @@
|
||||
/* global wpforms_challenge_admin, WPFormsUtils */
|
||||
/**
|
||||
* WPForms Challenge function.
|
||||
*
|
||||
* @since 1.5.0
|
||||
* @since 1.6.2 Challenge v2
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var WPFormsChallenge = window.WPFormsChallenge || {};
|
||||
|
||||
WPFormsChallenge.core = window.WPFormsChallenge.core || ( function( document, window, $ ) {
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var app = {};
|
||||
|
||||
/**
|
||||
* Runtime variables.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var vars = {};
|
||||
|
||||
/**
|
||||
* DOM elements.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var el = {};
|
||||
|
||||
/**
|
||||
* Timer functions and properties.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var timer = {
|
||||
|
||||
/**
|
||||
* Number of minutes to complete the challenge.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
initialSecondsLeft: WPFormsChallenge.admin.l10n.minutes_left * 60,
|
||||
|
||||
/**
|
||||
* Load timer ID.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @returns {string} ID from setInterval().
|
||||
*/
|
||||
loadId: function() {
|
||||
|
||||
return localStorage.getItem( 'wpformsChallengeTimerId' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Save timer ID.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param {number|string} id setInterval() ID to save.
|
||||
*/
|
||||
saveId: function( id ) {
|
||||
|
||||
localStorage.setItem( 'wpformsChallengeTimerId', id );
|
||||
},
|
||||
|
||||
/**
|
||||
* Run the timer.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param {number} secondsLeft Number of seconds left to complete the Challenge.
|
||||
*
|
||||
* @returns {string|void} ID from setInterval().
|
||||
*/
|
||||
run: function( secondsLeft ) {
|
||||
|
||||
if ( 5 === app.loadStep() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var timerId = setInterval( function() {
|
||||
|
||||
app.updateTimerUI( secondsLeft );
|
||||
secondsLeft--;
|
||||
if ( 0 > secondsLeft ) {
|
||||
timer.saveSecondsLeft( 0 );
|
||||
clearInterval( timerId );
|
||||
}
|
||||
}, 1000 );
|
||||
|
||||
timer.saveId( timerId );
|
||||
|
||||
return timerId;
|
||||
},
|
||||
|
||||
/**
|
||||
* Pause the timer.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
pause: function() {
|
||||
|
||||
var timerId;
|
||||
var elSeconds;
|
||||
var secondsLeft = timer.getSecondsLeft();
|
||||
|
||||
if ( 0 === secondsLeft || 5 === app.loadStep() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
timerId = timer.loadId();
|
||||
clearInterval( timerId );
|
||||
|
||||
elSeconds = $( '#wpforms-challenge-timer' ).data( 'seconds-left' );
|
||||
|
||||
if ( elSeconds ) {
|
||||
timer.saveSecondsLeft( elSeconds );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Resume the timer.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
resume: function() {
|
||||
|
||||
var timerId;
|
||||
var secondsLeft = timer.getSecondsLeft();
|
||||
|
||||
if ( 0 === secondsLeft || 5 === app.loadStep() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
timerId = timer.loadId();
|
||||
|
||||
if ( timerId ) {
|
||||
clearInterval( timerId );
|
||||
}
|
||||
|
||||
timer.run( secondsLeft );
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear all frontend saved timer data.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
clear: function() {
|
||||
|
||||
localStorage.removeItem( 'wpformsChallengeSecondsLeft' );
|
||||
localStorage.removeItem( 'wpformsChallengeTimerId' );
|
||||
localStorage.removeItem( 'wpformsChallengeTimerStatus' );
|
||||
$( '#wpforms-challenge-timer' ).removeData( 'seconds-left' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get number of seconds left to complete the Challenge.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @returns {number} Number of seconds left to complete the Challenge.
|
||||
*/
|
||||
getSecondsLeft: function() {
|
||||
|
||||
var secondsLeft = localStorage.getItem( 'wpformsChallengeSecondsLeft' );
|
||||
secondsLeft = parseInt( secondsLeft, 10 ) || 0;
|
||||
|
||||
return secondsLeft;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get number of seconds spent completing the Challenge.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param {number} secondsLeft Number of seconds left to complete the Challenge.
|
||||
*
|
||||
* @returns {number} Number of seconds spent completing the Challenge.
|
||||
*/
|
||||
getSecondsSpent: function( secondsLeft ) {
|
||||
|
||||
secondsLeft = secondsLeft || timer.getSecondsLeft();
|
||||
|
||||
return timer.initialSecondsLeft - secondsLeft;
|
||||
},
|
||||
|
||||
/**
|
||||
* Save number of seconds left to complete the Challenge.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param {number|string} secondsLeft Number of seconds left to complete the Challenge.
|
||||
*/
|
||||
saveSecondsLeft: function( secondsLeft ) {
|
||||
|
||||
localStorage.setItem( 'wpformsChallengeSecondsLeft', secondsLeft );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get 'minutes' part of timer display.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param {number} secondsLeft Number of seconds left to complete the Challenge.
|
||||
*
|
||||
* @returns {number} 'Minutes' part of timer display.
|
||||
*/
|
||||
getMinutesFormatted: function( secondsLeft ) {
|
||||
|
||||
secondsLeft = secondsLeft || timer.getSecondsLeft();
|
||||
|
||||
return Math.floor( secondsLeft / 60 );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get 'seconds' part of timer display.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param {number} secondsLeft Number of seconds left to complete the Challenge.
|
||||
*
|
||||
* @returns {number} 'Seconds' part of timer display.
|
||||
*/
|
||||
getSecondsFormatted: function( secondsLeft ) {
|
||||
|
||||
secondsLeft = secondsLeft || timer.getSecondsLeft();
|
||||
|
||||
return secondsLeft % 60;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get formatted timer for display.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param {number} secondsLeft Number of seconds left to complete the Challenge.
|
||||
*
|
||||
* @returns {string} Formatted timer for display.
|
||||
*/
|
||||
getFormatted: function( secondsLeft ) {
|
||||
|
||||
secondsLeft = secondsLeft || timer.getSecondsLeft();
|
||||
|
||||
var timerMinutes = timer.getMinutesFormatted( secondsLeft );
|
||||
var timerSeconds = timer.getSecondsFormatted( secondsLeft );
|
||||
|
||||
return timerMinutes + ( 9 < timerSeconds ? ':' : ':0' ) + timerSeconds;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*/
|
||||
app = {
|
||||
|
||||
/**
|
||||
* Public timer functions and properties.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
timer: timer,
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
init: function() {
|
||||
|
||||
$( app.ready );
|
||||
$( window ).on( 'load', function() {
|
||||
|
||||
// in case of jQuery 3.+ we need to wait for an `ready` event first.
|
||||
if ( typeof $.ready.then === 'function' ) {
|
||||
$.ready.then( app.load );
|
||||
} else {
|
||||
app.load();
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
ready: function() {
|
||||
|
||||
app.setup();
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Window load.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
load: function() {
|
||||
|
||||
if ( wpforms_challenge_admin.option.status === 'started' ) {
|
||||
app.timer.run( app.timer.getSecondsLeft() );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initial setup.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
setup: function() {
|
||||
|
||||
var secondsLeft;
|
||||
var timerId = app.timer.loadId();
|
||||
|
||||
if ( timerId ) {
|
||||
clearInterval( timerId );
|
||||
secondsLeft = app.timer.getSecondsLeft();
|
||||
}
|
||||
|
||||
if ( ! timerId || 0 === app.loadStep() || wpforms_challenge_admin.option.status === 'inited' ) {
|
||||
secondsLeft = app.timer.initialSecondsLeft;
|
||||
}
|
||||
|
||||
app.initElements();
|
||||
app.refreshStep();
|
||||
app.initListUI( null, true );
|
||||
app.updateListUI();
|
||||
app.updateTimerUI( secondsLeft );
|
||||
},
|
||||
|
||||
/**
|
||||
* Register JS events.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
events: function() {
|
||||
|
||||
$( [ window, document ] )
|
||||
.on( 'blur', app.pauseChallenge )
|
||||
.on( 'focus', app.resumeChallenge )
|
||||
.on( 'click', '.wpforms-challenge-done-btn', app.resumeChallenge );
|
||||
|
||||
el.$btnPause.on( 'click', app.pauseChallenge );
|
||||
el.$btnResume.on( 'click', app.resumeChallenge );
|
||||
|
||||
el.$listSteps.on( 'click', '.wpforms-challenge-item-current', app.refreshPage );
|
||||
},
|
||||
|
||||
/**
|
||||
* DOM elements.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
initElements: function() {
|
||||
|
||||
el = {
|
||||
$challenge: $( '.wpforms-challenge' ),
|
||||
$btnPause: $( '.wpforms-challenge-pause' ),
|
||||
$btnResume: $( '.wpforms-challenge-resume' ),
|
||||
$listSteps: $( '.wpforms-challenge-list' ),
|
||||
$listBlock: $( '.wpforms-challenge-list-block' ),
|
||||
$listBtnToggle: $( '.wpforms-challenge-list-block .toggle-list' ),
|
||||
$progressBar: $( '.wpforms-challenge-bar' ),
|
||||
$tooltipBtnDone: function() {
|
||||
return $( '.wpforms-challenge-tooltip .wpforms-challenge-done-btn' );
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Get last saved step.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @returns {number} Last saved step.
|
||||
*/
|
||||
loadStep: function() {
|
||||
|
||||
var step = localStorage.getItem( 'wpformsChallengeStep' );
|
||||
step = parseInt( step, 10 ) || 0;
|
||||
|
||||
return step;
|
||||
},
|
||||
|
||||
/**
|
||||
* Save Challenge step.
|
||||
*
|
||||
* @param {number|string} step Step to save.
|
||||
*
|
||||
* @returns {object} jqXHR object from saveChallengeOption().
|
||||
*/
|
||||
saveStep: function( step ) {
|
||||
|
||||
localStorage.setItem( 'wpformsChallengeStep', step );
|
||||
|
||||
return WPFormsChallenge.admin.saveChallengeOption( { step: step } );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update a step with backend data.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
refreshStep: function() {
|
||||
|
||||
var savedStep = el.$challenge.data( 'wpforms-challenge-saved-step' );
|
||||
savedStep = parseInt( savedStep, 10 ) || 0;
|
||||
|
||||
// Step saved on a backend has a priority.
|
||||
if ( app.loadStep() !== savedStep ) {
|
||||
app.saveStep( savedStep );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Complete Challenge step.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param {number|string} step Step to complete.
|
||||
*
|
||||
* @returns {object} jqXHR object from saveStep().
|
||||
*/
|
||||
stepCompleted: function( step ) {
|
||||
|
||||
app.updateListUI( step );
|
||||
app.updateTooltipUI( step );
|
||||
|
||||
return app.saveStep( step );
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize Challenge tooltips.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param {number|string} step Last saved step.
|
||||
* @param {string} anchor Element selector to bind tooltip to.
|
||||
* @param {Object} args Tooltipster arguments.
|
||||
*/
|
||||
initTooltips( step, anchor, args ) {
|
||||
if ( typeof $.fn.tooltipster === 'undefined' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $dot = $( '<span class="wpforms-challenge-dot wpforms-challenge-dot-step' + step + '" data-wpforms-challenge-step="' + step + '"> </span>' );
|
||||
const tooltipsterArgs = {
|
||||
content : $( '#tooltip-content' + step ),
|
||||
trigger : null,
|
||||
interactive : true,
|
||||
animationDuration: 0,
|
||||
delay : 0,
|
||||
theme : [ 'tooltipster-default', 'wpforms-challenge-tooltip' ],
|
||||
side : [ 'top' ],
|
||||
distance : 3,
|
||||
functionReady( instance, helper ) {
|
||||
$( helper.tooltip ).addClass( 'wpforms-challenge-tooltip-step' + step );
|
||||
|
||||
const isRTL = $( 'body' ).hasClass( 'rtl' );
|
||||
|
||||
// Custom positioning.
|
||||
if ( step === 4 || step === 3 ) {
|
||||
instance.option( 'side', isRTL ? 'left' : 'right' );
|
||||
} else if ( step === 1 ) {
|
||||
instance.option( 'side', isRTL ? 'right' : 'left' );
|
||||
}
|
||||
|
||||
// Reposition is needed to render max-width CSS correctly.
|
||||
instance.reposition();
|
||||
},
|
||||
};
|
||||
|
||||
if ( typeof args === 'object' && args !== null ) {
|
||||
$.extend( tooltipsterArgs, args );
|
||||
}
|
||||
|
||||
$dot.insertAfter( anchor ).tooltipster( tooltipsterArgs );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update tooltips appearance.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param {number|string} step Last saved step.
|
||||
*/
|
||||
updateTooltipUI: function( step ) {
|
||||
|
||||
var nextStep;
|
||||
|
||||
step = step || app.loadStep();
|
||||
nextStep = step + 1;
|
||||
|
||||
$( '.wpforms-challenge-dot' ).each( function( i, el ) {
|
||||
|
||||
var $dot = $( el ),
|
||||
elStep = $dot.data( 'wpforms-challenge-step' );
|
||||
|
||||
if ( elStep < nextStep ) {
|
||||
$dot.addClass( 'wpforms-challenge-dot-completed' );
|
||||
}
|
||||
|
||||
if ( elStep > nextStep ) {
|
||||
$dot.addClass( 'wpforms-challenge-dot-next' );
|
||||
}
|
||||
|
||||
if ( elStep === nextStep ) {
|
||||
$dot.removeClass( 'wpforms-challenge-dot-completed wpforms-challenge-dot-next' );
|
||||
}
|
||||
|
||||
// Zero timeout is needed to properly detect $el visibility.
|
||||
setTimeout( function() {
|
||||
if ( $dot.is( ':visible' ) && elStep === nextStep ) {
|
||||
$dot.tooltipster( 'open' );
|
||||
} else {
|
||||
$dot.tooltipster( 'close' );
|
||||
}
|
||||
}, 0 );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Init ListUI.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*
|
||||
* @param {number|string} status Challenge status.
|
||||
* @param {boolean} initial Initial run, false by default.
|
||||
*/
|
||||
initListUI: function( status, initial ) {
|
||||
|
||||
status = status || wpforms_challenge_admin.option.status;
|
||||
|
||||
if ( [ 'started', 'paused' ].indexOf( status ) > -1 ) {
|
||||
el.$listBlock.find( 'p' ).hide();
|
||||
el.$listBtnToggle.show();
|
||||
el.$progressBar.show();
|
||||
|
||||
// Transform skip button to cancel button.
|
||||
var $skipBtn = el.$listBlock.find( '.list-block-button.challenge-skip' );
|
||||
|
||||
$skipBtn
|
||||
.attr( 'title', $skipBtn.data( 'cancel-title' ) )
|
||||
.removeClass( 'challenge-skip' )
|
||||
.addClass( 'challenge-cancel' );
|
||||
}
|
||||
|
||||
// Set initial window closed (collapsed) state if window is short or if it is closed manually.
|
||||
if (
|
||||
initial &&
|
||||
(
|
||||
( $( window ).height() < 900 && wpforms_challenge_admin.option.window_closed === '' ) ||
|
||||
wpforms_challenge_admin.option.window_closed === '1'
|
||||
)
|
||||
) {
|
||||
el.$listBlock.find( 'p' ).hide();
|
||||
el.$listBtnToggle.trigger( 'click' );
|
||||
}
|
||||
|
||||
if ( status === 'paused' ) {
|
||||
|
||||
el.$challenge.addClass( 'paused' );
|
||||
el.$btnPause.hide();
|
||||
el.$btnResume.show();
|
||||
|
||||
} else {
|
||||
|
||||
// Zero timeout is needed to avoid firing 'focus' and 'click' events in the same loop.
|
||||
setTimeout( function() {
|
||||
el.$btnPause.show();
|
||||
}, 0 );
|
||||
|
||||
el.$challenge.removeClass( 'paused' );
|
||||
el.$btnResume.hide();
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update Challenge task list appearance.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param {number|string} step Last saved step.
|
||||
*/
|
||||
updateListUI: function( step ) {
|
||||
|
||||
step = step || app.loadStep();
|
||||
|
||||
el.$listSteps.find( 'li' ).slice( 0, step ).addClass( 'wpforms-challenge-item-completed' ).removeClass( 'wpforms-challenge-item-current' );
|
||||
el.$listSteps.find( 'li' ).eq( step ).addClass( 'wpforms-challenge-item-current' );
|
||||
el.$progressBar.find( 'div' ).css( 'width', ( step * 20 ) + '%' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update Challenge timer appearance.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param {number} secondsLeft Number of seconds left to complete the Challenge.
|
||||
*/
|
||||
updateTimerUI: function( secondsLeft ) {
|
||||
|
||||
if ( ! secondsLeft || isNaN( secondsLeft ) || '0' === secondsLeft ) {
|
||||
secondsLeft = 0;
|
||||
}
|
||||
|
||||
app.timer.saveSecondsLeft( secondsLeft );
|
||||
$( '#wpforms-challenge-timer' ).text( app.timer.getFormatted( secondsLeft ) ).data( 'seconds-left', secondsLeft );
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove Challenge interface.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
removeChallengeUI: function() {
|
||||
|
||||
$( '.wpforms-challenge-dot' ).remove();
|
||||
el.$challenge.remove();
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear all Challenge frontend saved data.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
clearLocalStorage: function() {
|
||||
|
||||
localStorage.removeItem( 'wpformsChallengeStep' );
|
||||
app.timer.clear();
|
||||
},
|
||||
|
||||
/**
|
||||
* Pause Challenge.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*
|
||||
* @param {object} e Event object.
|
||||
*/
|
||||
pauseChallenge: function( e ) {
|
||||
|
||||
// Skip if out to the iframe.
|
||||
if ( document.activeElement.tagName === 'IFRAME' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip if is not started.
|
||||
if ( wpforms_challenge_admin.option.status !== 'started' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
vars.pauseEvent = e.type;
|
||||
|
||||
app.pauseResumeChallenge( 'pause' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Resume Challenge.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*
|
||||
* @param {object} e Event object.
|
||||
*
|
||||
* @returns {Function|void} Return pause challenge function or void.
|
||||
*/
|
||||
resumeChallenge: function( e ) {
|
||||
|
||||
// Skip if is not paused.
|
||||
if ( wpforms_challenge_admin.option.status !== 'paused' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Resume on 'focus' only if it has been paused on 'blur'.
|
||||
if ( e.type === 'focus' && vars.pauseEvent !== 'blur' ) {
|
||||
delete vars.pauseEvent;
|
||||
return;
|
||||
}
|
||||
|
||||
vars.resumeEvent = e.type;
|
||||
|
||||
return app.pauseResumeChallenge( 'resume' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Pause/Resume Challenge.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*
|
||||
* @param {string} action Action to perform. `pause` or `resume`.
|
||||
*
|
||||
* @returns {Function} Save challenge option.
|
||||
*/
|
||||
pauseResumeChallenge: function( action ) {
|
||||
|
||||
action = action === 'pause' ? action : 'resume';
|
||||
|
||||
app.timer[ action ]();
|
||||
|
||||
var optionData = {
|
||||
status : action === 'pause' ? 'paused' : 'started',
|
||||
seconds_spent: app.timer.getSecondsSpent(),
|
||||
seconds_left : app.timer.getSecondsLeft(),
|
||||
};
|
||||
|
||||
app.initListUI( optionData.status );
|
||||
|
||||
return WPFormsChallenge.admin.saveChallengeOption( optionData );
|
||||
},
|
||||
|
||||
/**
|
||||
* Resume Challenge and execute the callback.
|
||||
*
|
||||
* @since 1.7.5
|
||||
*
|
||||
* @param {object} e Event object.
|
||||
* @param {Function} callback Callback function.
|
||||
*/
|
||||
resumeChallengeAndExec: function( e, callback ) {
|
||||
|
||||
if ( typeof callback !== 'function' ) {
|
||||
callback = function() {};
|
||||
}
|
||||
|
||||
if ( wpforms_challenge_admin.option.status !== 'paused' ) {
|
||||
callback();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var resumeResult = app.resumeChallenge( e );
|
||||
|
||||
if ( typeof resumeResult === 'object' && typeof resumeResult.done === 'function' ) {
|
||||
resumeResult.done( callback );
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Freeze/Unfreeze Challenge.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {boolean} freeze True to freeze, false to unfreeze.
|
||||
* @param {string} tooltipText Tooltip text.
|
||||
*/
|
||||
async freezeChallenge( freeze = true, tooltipText = '' ) {
|
||||
// Freeze the Challenge.
|
||||
if ( freeze ) {
|
||||
const closed = el.$listBlock.hasClass( 'closed' );
|
||||
|
||||
el.$challenge.addClass( 'frozen' ).data( 'was-closed', closed );
|
||||
el.$listBlock.addClass( 'closed' ).find( 'p' ).hide();
|
||||
app.initFrozenTooltip( tooltipText.length ? tooltipText : wpforms_challenge_admin.frozen_tooltip );
|
||||
app.pauseResumeChallenge( 'pause' );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not unfreeze if it's not frozen.
|
||||
if ( ! el.$challenge.hasClass( 'frozen' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Unfreeze the Challenge.
|
||||
el.$challenge.removeClass( 'frozen' );
|
||||
el.$progressBar.tooltipster( 'close' );
|
||||
app.pauseResumeChallenge( 'resume' );
|
||||
|
||||
// Restore the opened state.
|
||||
if ( ! el.$challenge.data( 'was-closed' ) ) {
|
||||
el.$listBlock.removeClass( 'closed' ).find( 'p' ).show();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Init the frozen Challenge tooltip.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {string} tooltipText Tooltip text.
|
||||
*/
|
||||
initFrozenTooltip( tooltipText ) {
|
||||
let instance = el.$progressBar.data( 'tooltipster' );
|
||||
|
||||
if ( ! instance ) {
|
||||
const args = {
|
||||
content: '',
|
||||
trigger: 'manual',
|
||||
interactive: false,
|
||||
animationDuration: 100,
|
||||
maxWidth: 230,
|
||||
delay: 0,
|
||||
distance: 36,
|
||||
side: [ 'top' ],
|
||||
theme: [ 'tooltipster-default', 'wpforms-challenge-frozen-tooltip' ],
|
||||
contentAsHTML: true,
|
||||
};
|
||||
|
||||
// Initialize.
|
||||
el.$progressBar.tooltipster( args );
|
||||
instance = el.$progressBar.tooltipster( 'instance' );
|
||||
el.$progressBar.data( 'tooltipster', instance );
|
||||
}
|
||||
|
||||
el.$challenge.show();
|
||||
instance.content( tooltipText );
|
||||
instance.open();
|
||||
},
|
||||
|
||||
/**
|
||||
* Refresh Page in order to re-init current step.
|
||||
*
|
||||
* @since 1.6.2
|
||||
* @since 1.9.8 Added `wpformsChallengeCoreBeforeRefreshPage` event.
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
*/
|
||||
refreshPage( e ) {
|
||||
const customEvent = WPFormsUtils.triggerEvent( $( document ), 'wpformsChallengeCoreBeforeRefreshPage', e );
|
||||
|
||||
// If preventDefault was called, skip reloading.
|
||||
if ( customEvent.isDefaultPrevented() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.reload( true );
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if we're in Gutenberg editor.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @returns {boolean} Is Gutenberg or not.
|
||||
*/
|
||||
isGutenberg: function() {
|
||||
|
||||
return typeof wp !== 'undefined' && Object.prototype.hasOwnProperty.call( wp, 'blocks' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Trigger form embed page save potentially reloading it.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
triggerPageSave: function() {
|
||||
|
||||
if ( app.isGutenberg() ) {
|
||||
app.gutenbergPageSave();
|
||||
|
||||
} else {
|
||||
$( '#post #publish' ).trigger( 'click' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Save page for Gutenberg.
|
||||
*
|
||||
* @since 1.5.2
|
||||
*/
|
||||
gutenbergPageSave: function() {
|
||||
|
||||
var $gb = $( '.block-editor' ),
|
||||
$updateBtn = $gb.find( '.editor-post-publish-button.editor-post-publish-button__button' );
|
||||
|
||||
// Trigger click on the Update button.
|
||||
if ( $updateBtn.length > 0 ) {
|
||||
$updateBtn.trigger( 'click' );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Use MutationObserver to wait while Gutenberg create/display panel with Publish button.
|
||||
var obs = {
|
||||
targetNode : $gb.find( '.edit-post-layout, .block-editor-editor-skeleton__publish > div' )[0],
|
||||
config : {
|
||||
childList: true,
|
||||
attributes: true,
|
||||
subtree: true,
|
||||
},
|
||||
};
|
||||
|
||||
obs.callback = function( mutationsList, observer ) {
|
||||
|
||||
var $btn = $gb.find( '.editor-post-publish-button, .editor-post-publish-panel__header-publish-button .editor-post-publish-button__button' );
|
||||
|
||||
if ( $btn.length > 0 ) {
|
||||
$btn.trigger( 'click' );
|
||||
observer.disconnect();
|
||||
}
|
||||
};
|
||||
|
||||
obs.observer = new MutationObserver( obs.callback );
|
||||
obs.observer.observe( obs.targetNode, obs.config );
|
||||
|
||||
// Trigger click on the Publish button that opens the additional publishing panel.
|
||||
$gb.find( '.edit-post-toggle-publish-panel__button, .editor-post-publish-panel__toggle.editor-post-publish-button__button' )
|
||||
.trigger( 'click' );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
WPFormsChallenge.core.init();
|
||||
+1
File diff suppressed because one or more lines are too long
+352
@@ -0,0 +1,352 @@
|
||||
/* global ajaxurl */
|
||||
/**
|
||||
* WPForms Challenge function.
|
||||
*
|
||||
* @since 1.5.0
|
||||
* @since 1.6.2 Challenge v2.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var WPFormsChallenge = window.WPFormsChallenge || {};
|
||||
|
||||
WPFormsChallenge.embed = window.WPFormsChallenge.embed || ( function( document, window, $ ) {
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
init: function() {
|
||||
|
||||
$( app.ready );
|
||||
$( window ).on( 'load', function() {
|
||||
|
||||
// in case of jQuery 3.+ we need to wait for an `ready` event first.
|
||||
if ( typeof $.ready.then === 'function' ) {
|
||||
$.ready.then( app.load );
|
||||
} else {
|
||||
app.load();
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
ready: function() {
|
||||
|
||||
app.setup();
|
||||
app.events();
|
||||
app.observeFullscreenMode();
|
||||
},
|
||||
|
||||
/**
|
||||
* Window load.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
load() {
|
||||
// If the page is Add new page.
|
||||
if ( window.location.href.indexOf( 'post-new.php' ) > -1 ) {
|
||||
app.lastStep();
|
||||
$( '.wpforms-challenge-dot-completed' ).hide();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( WPFormsChallenge.core.isGutenberg() ) {
|
||||
// Wait for the Gutenberg header to be present before initializing tooltips.
|
||||
app.onElementReady( '.block-editor .edit-post-header', function() {
|
||||
WPFormsChallenge.core.initTooltips( 5, '.block-editor .edit-post-header', { side: 'bottom' } );
|
||||
app.updateTooltipVisibility();
|
||||
WPFormsChallenge.core.updateTooltipUI();
|
||||
} );
|
||||
} else {
|
||||
WPFormsChallenge.core.initTooltips( 5, '.wpforms-insert-form-button', { side: 'right' } );
|
||||
WPFormsChallenge.core.updateTooltipUI();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initial setup.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
setup: function() {
|
||||
|
||||
if ( 5 === WPFormsChallenge.core.loadStep() ) {
|
||||
$( '.wpforms-challenge' ).addClass( 'wpforms-challenge-completed' );
|
||||
app.showPopup();
|
||||
}
|
||||
|
||||
$( '.wpforms-challenge' ).show();
|
||||
},
|
||||
|
||||
/**
|
||||
* Register JS events.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
events: function() {
|
||||
|
||||
$( '.wpforms-challenge-step5-done' )
|
||||
.on( 'click', app.lastStep );
|
||||
|
||||
$( '.wpforms-challenge-popup-close, .wpforms-challenge-end' )
|
||||
.on( 'click', app.completeChallenge );
|
||||
|
||||
$( '#wpforms-challenge-contact-form .wpforms-challenge-popup-contact-btn' )
|
||||
.on( 'click', app.submitContactForm );
|
||||
},
|
||||
|
||||
/**
|
||||
* Last step done routine.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
lastStep: function() {
|
||||
|
||||
WPFormsChallenge.core.timer.pause();
|
||||
WPFormsChallenge.core.stepCompleted( 5 );
|
||||
$( '.wpforms-challenge' ).addClass( 'wpforms-challenge-completed' );
|
||||
app.showPopup();
|
||||
},
|
||||
|
||||
/**
|
||||
* Show either 'Congratulations' or 'Contact Us' popup.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
showPopup: function() {
|
||||
|
||||
var secondsLeft = WPFormsChallenge.core.timer.getSecondsLeft();
|
||||
|
||||
$( '.wpforms-challenge-popup-container' ).show();
|
||||
|
||||
if ( 0 < secondsLeft ) {
|
||||
var secondsSpent = WPFormsChallenge.core.timer.getSecondsSpent( secondsLeft );
|
||||
|
||||
$( '#wpforms-challenge-congrats-minutes' )
|
||||
.text( WPFormsChallenge.core.timer.getMinutesFormatted( secondsSpent ) );
|
||||
$( '#wpforms-challenge-congrats-seconds' )
|
||||
.text( WPFormsChallenge.core.timer.getSecondsFormatted( secondsSpent ) );
|
||||
$( '#wpforms-challenge-congrats-popup' ).show();
|
||||
} else {
|
||||
$( '#wpforms-challenge-contact-popup' ).show();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide the popup.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
hidePopup: function() {
|
||||
|
||||
$( '.wpforms-challenge-popup-container' ).hide();
|
||||
$( '.wpforms-challenge-popup' ).hide();
|
||||
},
|
||||
|
||||
/**
|
||||
* Complete Challenge.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
completeChallenge: function() {
|
||||
|
||||
var optionData = {
|
||||
status : 'completed',
|
||||
seconds_spent: WPFormsChallenge.core.timer.getSecondsSpent(),
|
||||
seconds_left : WPFormsChallenge.core.timer.getSecondsLeft(),
|
||||
};
|
||||
|
||||
app.hidePopup();
|
||||
|
||||
WPFormsChallenge.core.removeChallengeUI();
|
||||
WPFormsChallenge.core.clearLocalStorage();
|
||||
|
||||
WPFormsChallenge.admin.saveChallengeOption( optionData )
|
||||
.done( WPFormsChallenge.core.triggerPageSave ); // Save and reload the page to remove WPForms Challenge JS.
|
||||
},
|
||||
|
||||
/**
|
||||
* Submit contact form button click event handler.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*
|
||||
* @param {object} e Event object.
|
||||
*/
|
||||
submitContactForm: function( e ) {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
var $btn = $( this ),
|
||||
$form = $btn.closest( '#wpforms-challenge-contact-form' );
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
var data = {
|
||||
action : 'wpforms_challenge_send_contact_form',
|
||||
_wpnonce : WPFormsChallenge.admin.l10n.nonce,
|
||||
contact_data: {
|
||||
message : $form.find( '.wpforms-challenge-contact-message' ).val(),
|
||||
contact_me: $form.find( '.wpforms-challenge-contact-permission' ).prop( 'checked' ),
|
||||
},
|
||||
};
|
||||
/* eslint-enable */
|
||||
|
||||
$btn.prop( 'disabled', true );
|
||||
|
||||
$.post( ajaxurl, data, function( response ) {
|
||||
|
||||
if ( ! response.success ) {
|
||||
console.error( 'Error sending WPForms Challenge Contact Form.' );
|
||||
}
|
||||
} ).done( app.completeChallenge );
|
||||
},
|
||||
|
||||
/**
|
||||
* Observe Gutenberg's Fullscreen Mode state to adjust tooltip positioning.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
observeFullscreenMode: function() {
|
||||
|
||||
var $body = $( 'body' ),
|
||||
isFullScreenPrev = $body.hasClass( 'is-fullscreen-mode' );
|
||||
|
||||
// MutationObserver configuration and callback.
|
||||
var obs = {
|
||||
targetNode : $body[0],
|
||||
config : {
|
||||
attributes: true,
|
||||
},
|
||||
};
|
||||
|
||||
obs.callback = function( mutationsList, observer ) {
|
||||
|
||||
var mutation,
|
||||
isFullScreen,
|
||||
$step5 = $( '.wpforms-challenge-tooltip-step5' ),
|
||||
$step5Arrow = $step5.find( '.tooltipster-arrow' );
|
||||
|
||||
for ( var i in mutationsList ) {
|
||||
mutation = mutationsList[ i ];
|
||||
if ( mutation.type !== 'attributes' || mutation.attributeName !== 'class' ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
isFullScreen = $body.hasClass( 'is-fullscreen-mode' );
|
||||
if ( isFullScreen === isFullScreenPrev ) {
|
||||
continue;
|
||||
}
|
||||
isFullScreenPrev = isFullScreen;
|
||||
|
||||
if ( isFullScreen ) {
|
||||
$step5.css( {
|
||||
'top': '93px',
|
||||
'left': '0',
|
||||
} );
|
||||
$step5Arrow.css( 'left', '91px' );
|
||||
} else {
|
||||
$step5.css( {
|
||||
'top': '125px',
|
||||
'left': '66px',
|
||||
} );
|
||||
$step5Arrow.css( 'left', '130px' );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
obs.observer = new MutationObserver( obs.callback );
|
||||
obs.observer.observe( obs.targetNode, obs.config );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update tooltip z-index when Gutenberg sidebar is open.
|
||||
*
|
||||
* @since 1.7.4
|
||||
*
|
||||
* @returns {Function} Default function.
|
||||
*/
|
||||
updateTooltipVisibility: function() {
|
||||
|
||||
var targetNode = document.querySelector( '.interface-interface-skeleton__body' );
|
||||
|
||||
if ( targetNode === null ) {
|
||||
return app.updateTooltipVisibilityDefault();
|
||||
}
|
||||
|
||||
var observer = new MutationObserver( function( mutationsList ) {
|
||||
|
||||
var $step5 = $( '.wpforms-challenge-tooltip-step5' );
|
||||
|
||||
for ( var mutation of mutationsList ) {
|
||||
|
||||
if ( mutation.type === 'childList' ) {
|
||||
$step5.toggleClass( 'wpforms-challenge-tooltip-step5-hide' );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
observer.observe( targetNode, { attributes: true, childList: true } );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update tooltip visibility for WP 5.6 version.
|
||||
*
|
||||
* @since 1.7.4
|
||||
*/
|
||||
updateTooltipVisibilityDefault: function() {
|
||||
|
||||
$( '.editor-inserter__toggle' ).on( 'click', function() {
|
||||
|
||||
$( '.wpforms-challenge-tooltip-step5' ).toggleClass( 'wpforms-challenge-tooltip-step5-hide' );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Wait until a DOM element matching selector exists, then run callback.
|
||||
* Uses MutationObserver for Gutenberg, which mounts after a window load.
|
||||
*
|
||||
* @since 1.9.8
|
||||
*
|
||||
* @param {string} selector CSS selector to wait for.
|
||||
* @param {Function} callback Callback receiving the found element.
|
||||
*/
|
||||
onElementReady( selector, callback ) {
|
||||
const node = document.querySelector( selector );
|
||||
if ( node ) {
|
||||
callback( node );
|
||||
return;
|
||||
}
|
||||
|
||||
const observer = new MutationObserver( function() {
|
||||
const el = document.querySelector( selector );
|
||||
if ( el ) {
|
||||
observer.disconnect();
|
||||
callback( el );
|
||||
}
|
||||
} );
|
||||
|
||||
observer.observe( document.documentElement || document.body, { childList: true, subtree: true } );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPFormsChallenge.embed.init();
|
||||
Vendored
Executable
+1
@@ -0,0 +1 @@
|
||||
var WPFormsChallenge=window.WPFormsChallenge||{};WPFormsChallenge.embed=window.WPFormsChallenge.embed||((n,e,c)=>{var t={init:function(){c(t.ready),c(e).on("load",function(){"function"==typeof c.ready.then?c.ready.then(t.load):t.load()})},ready:function(){t.setup(),t.events(),t.observeFullscreenMode()},load(){-1<e.location.href.indexOf("post-new.php")?(t.lastStep(),c(".wpforms-challenge-dot-completed").hide()):WPFormsChallenge.core.isGutenberg()?t.onElementReady(".block-editor .edit-post-header",function(){WPFormsChallenge.core.initTooltips(5,".block-editor .edit-post-header",{side:"bottom"}),t.updateTooltipVisibility(),WPFormsChallenge.core.updateTooltipUI()}):(WPFormsChallenge.core.initTooltips(5,".wpforms-insert-form-button",{side:"right"}),WPFormsChallenge.core.updateTooltipUI())},setup:function(){5===WPFormsChallenge.core.loadStep()&&(c(".wpforms-challenge").addClass("wpforms-challenge-completed"),t.showPopup()),c(".wpforms-challenge").show()},events:function(){c(".wpforms-challenge-step5-done").on("click",t.lastStep),c(".wpforms-challenge-popup-close, .wpforms-challenge-end").on("click",t.completeChallenge),c("#wpforms-challenge-contact-form .wpforms-challenge-popup-contact-btn").on("click",t.submitContactForm)},lastStep:function(){WPFormsChallenge.core.timer.pause(),WPFormsChallenge.core.stepCompleted(5),c(".wpforms-challenge").addClass("wpforms-challenge-completed"),t.showPopup()},showPopup:function(){var e=WPFormsChallenge.core.timer.getSecondsLeft();c(".wpforms-challenge-popup-container").show(),(0<e?(e=WPFormsChallenge.core.timer.getSecondsSpent(e),c("#wpforms-challenge-congrats-minutes").text(WPFormsChallenge.core.timer.getMinutesFormatted(e)),c("#wpforms-challenge-congrats-seconds").text(WPFormsChallenge.core.timer.getSecondsFormatted(e)),c("#wpforms-challenge-congrats-popup")):c("#wpforms-challenge-contact-popup")).show()},hidePopup:function(){c(".wpforms-challenge-popup-container").hide(),c(".wpforms-challenge-popup").hide()},completeChallenge:function(){var e={status:"completed",seconds_spent:WPFormsChallenge.core.timer.getSecondsSpent(),seconds_left:WPFormsChallenge.core.timer.getSecondsLeft()};t.hidePopup(),WPFormsChallenge.core.removeChallengeUI(),WPFormsChallenge.core.clearLocalStorage(),WPFormsChallenge.admin.saveChallengeOption(e).done(WPFormsChallenge.core.triggerPageSave)},submitContactForm:function(e){e.preventDefault();var e=c(this),o=e.closest("#wpforms-challenge-contact-form"),o={action:"wpforms_challenge_send_contact_form",_wpnonce:WPFormsChallenge.admin.l10n.nonce,contact_data:{message:o.find(".wpforms-challenge-contact-message").val(),contact_me:o.find(".wpforms-challenge-contact-permission").prop("checked")}};e.prop("disabled",!0),c.post(ajaxurl,o,function(e){e.success||console.error("Error sending WPForms Challenge Contact Form.")}).done(t.completeChallenge)},observeFullscreenMode:function(){var r=c("body"),a=r.hasClass("is-fullscreen-mode"),e={targetNode:r[0],config:{attributes:!0},callback:function(e,o){var t,l,n=c(".wpforms-challenge-tooltip-step5"),s=n.find(".tooltipster-arrow");for(l in e)"attributes"===(t=e[l]).type&&"class"===t.attributeName&&(t=r.hasClass("is-fullscreen-mode"))!==a&&((a=t)?(n.css({top:"93px",left:"0"}),s.css("left","91px")):(n.css({top:"125px",left:"66px"}),s.css("left","130px")))}};e.observer=new MutationObserver(e.callback),e.observer.observe(e.targetNode,e.config)},updateTooltipVisibility:function(){var e=n.querySelector(".interface-interface-skeleton__body");if(null===e)return t.updateTooltipVisibilityDefault();new MutationObserver(function(e){var o,t=c(".wpforms-challenge-tooltip-step5");for(o of e)"childList"===o.type&&t.toggleClass("wpforms-challenge-tooltip-step5-hide")}).observe(e,{attributes:!0,childList:!0})},updateTooltipVisibilityDefault:function(){c(".editor-inserter__toggle").on("click",function(){c(".wpforms-challenge-tooltip-step5").toggleClass("wpforms-challenge-tooltip-step5-hide")})},onElementReady(t,l){var e=n.querySelector(t);if(e)l(e);else{let o=new MutationObserver(function(){var e=n.querySelector(t);e&&(o.disconnect(),l(e))});o.observe(n.documentElement||n.body,{childList:!0,subtree:!0})}}};return t})(document,window,jQuery),WPFormsChallenge.embed.init();
|
||||
@@ -0,0 +1,789 @@
|
||||
/* global wpforms_education, WPFormsBuilder, wpf */
|
||||
|
||||
/**
|
||||
* WPForms Education Core.
|
||||
*
|
||||
* @since 1.6.6
|
||||
*/
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
/**
|
||||
* @param wpforms_education.activate_confirm
|
||||
* @param wpforms_education.activate_prompt
|
||||
* @param wpforms_education.activating
|
||||
* @param wpforms_education.addon_activated
|
||||
* @param wpforms_education.addon_error
|
||||
* @param wpforms_education.addon_incompatible.title
|
||||
* @param wpforms_education.addon_incompatible.button_text
|
||||
* @param wpforms_education.addon_incompatible.button_url
|
||||
* @param wpforms_education.ajax_url
|
||||
* @param wpforms_education.can_activate_addons
|
||||
* @param wpforms_education.can_install_addons
|
||||
* @param wpforms_education.cancel
|
||||
* @param wpforms_education.close
|
||||
* @param wpforms_education.install_confirm
|
||||
* @param wpforms_education.install_prompt
|
||||
* @param wpforms_education.installing
|
||||
* @param wpforms_education.nonce
|
||||
* @param wpforms_education.ok
|
||||
* @param wpforms_education.plugin_activated
|
||||
* @param wpforms_education.save_confirm
|
||||
* @param wpforms_education.save_prompt
|
||||
* @param wpforms_education.saving
|
||||
* @param wpforms_education.thanks_for_interest
|
||||
* @param wpforms_education.upgrade
|
||||
* @param wpforms_education.upgrade.modal
|
||||
* @param wpforms_education.upgrade.url
|
||||
* @param wpforms_education.upgrade.url_template
|
||||
*/
|
||||
|
||||
var WPFormsEducation = window.WPFormsEducation || {}; // eslint-disable-line no-var
|
||||
|
||||
WPFormsEducation.core = window.WPFormsEducation.core || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Spinner markup.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
const spinner = '<i class="wpforms-loading-spinner wpforms-loading-white wpforms-loading-inline"></i>';
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.6.6
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.6.6
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.6.6
|
||||
*/
|
||||
ready() {
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Register JS events.
|
||||
*
|
||||
* @since 1.6.6
|
||||
*/
|
||||
events() {
|
||||
app.dismissEvents();
|
||||
app.openModalButtonClick();
|
||||
app.setDykColspan();
|
||||
app.gotoAdvancedTabClick();
|
||||
app.proFieldDelete();
|
||||
},
|
||||
|
||||
/**
|
||||
* Open education modal.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*/
|
||||
openModalButtonClick() {
|
||||
$( document )
|
||||
.on( 'click', '.education-modal:not(.wpforms-add-fields-button)', app.openModalButtonHandler )
|
||||
.on( 'mousedown', '.education-modal.wpforms-add-fields-button', app.openModalButtonHandler )
|
||||
.on( 'click', '.education-action-button', app.actionButtonHandler );
|
||||
},
|
||||
|
||||
/**
|
||||
* Action button click handler.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*
|
||||
* @param {Event} event Event.
|
||||
*/
|
||||
actionButtonHandler( event ) {
|
||||
event.preventDefault();
|
||||
|
||||
const $this = $( this );
|
||||
const action = $this.data( 'action' );
|
||||
|
||||
// Currently, only the upgrade action is supported.
|
||||
if ( action !== 'upgrade' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const utmContent = $this.data( 'utm-content' );
|
||||
const type = $this.data( 'license' );
|
||||
|
||||
window.open( WPFormsEducation.core.getUpgradeURL( utmContent, type ), '_blank' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Open education modal handler.
|
||||
*
|
||||
* @since 1.8.0
|
||||
* @since 1.9.6.1 Added `$element` parameter.
|
||||
*
|
||||
* @param {Event} event Event.
|
||||
* @param {jQuery} $element jQuery element.
|
||||
*/
|
||||
openModalButtonHandler( event, $element = null ) {
|
||||
event.preventDefault();
|
||||
|
||||
const $this = $element || $( this );
|
||||
|
||||
switch ( $this.data( 'action' ) ) {
|
||||
case 'activate':
|
||||
app.activateModal( $this );
|
||||
break;
|
||||
case 'install':
|
||||
app.installModal( $this );
|
||||
break;
|
||||
case 'incompatible':
|
||||
app.incompatibleModal( $this );
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide Pro fields notice when all disabled fields deleted.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*/
|
||||
proFieldDelete() {
|
||||
$( '#wpforms-builder' ).on(
|
||||
'wpformsFieldDelete',
|
||||
function() {
|
||||
if ( ! $( '.wpforms-field-wrap .wpforms-field-is-pro' ).length ) {
|
||||
$( '.wpforms-preview .wpforms-pro-fields-notice' ).addClass( 'wpforms-hidden' );
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Dismiss button events.
|
||||
*
|
||||
* @since 1.6.6
|
||||
*/
|
||||
dismissEvents() {
|
||||
$( document ).on( 'click', '.wpforms-dismiss-container .wpforms-dismiss-button', function() {
|
||||
const $this = $( this ),
|
||||
$cont = $this.closest( '.wpforms-dismiss-container' ),
|
||||
data = {
|
||||
action: 'wpforms_education_dismiss',
|
||||
nonce: wpforms_education.nonce,
|
||||
section: $this.data( 'section' ),
|
||||
page: typeof window.pagenow === 'string' ? window.pagenow : '',
|
||||
};
|
||||
let $out = $cont.find( '.wpforms-dismiss-out' );
|
||||
|
||||
if ( $cont.hasClass( 'wpforms-dismiss-out' ) ) {
|
||||
$out = $cont;
|
||||
}
|
||||
|
||||
if ( $out.length > 0 ) {
|
||||
$out.addClass( 'out' );
|
||||
setTimeout(
|
||||
function() {
|
||||
$cont.remove();
|
||||
},
|
||||
300
|
||||
);
|
||||
} else {
|
||||
$cont.remove();
|
||||
}
|
||||
|
||||
$.post( wpforms_education.ajax_url, data );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate and dynamically set the DYK block cell colspan attribute.
|
||||
*
|
||||
* @since 1.7.3
|
||||
*/
|
||||
setDykColspan() {
|
||||
$( '#adv-settings' ).on(
|
||||
'change',
|
||||
'input.hide-column-tog',
|
||||
function() {
|
||||
const $dykCell = $( '.wpforms-dyk td' ),
|
||||
colCount = $( '.wp-list-table thead .manage-column' ).not( '.hidden' ).length;
|
||||
|
||||
$dykCell.attr( 'colspan', colCount );
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Go to Advanced tab when click on the link in Calculations educational notice.
|
||||
*
|
||||
* @since 1.8.4.1
|
||||
*/
|
||||
gotoAdvancedTabClick() {
|
||||
$( document )
|
||||
.on( 'click', '.wpforms-educational-alert.wpforms-calculations a', function( e ) {
|
||||
const $a = $( this );
|
||||
|
||||
if ( $a.attr( 'href' ) !== '#advanced-tab' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
$a.closest( '.wpforms-field-option' )
|
||||
.find( '.wpforms-field-option-group-advanced .wpforms-field-option-group-toggle' )
|
||||
.trigger( 'click' );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get UTM content for different elements.
|
||||
*
|
||||
* @since 1.6.9
|
||||
*
|
||||
* @param {jQuery} $el Element.
|
||||
*
|
||||
* @return {string} UTM content string.
|
||||
*/
|
||||
getUTMContentValue( $el ) {
|
||||
// UTM content for Fields.
|
||||
if ( $el.hasClass( 'wpforms-add-fields-button' ) ) {
|
||||
return $el.data( 'utm-content' ) + ' Field';
|
||||
}
|
||||
|
||||
// UTM content for Templates.
|
||||
if ( $el.hasClass( 'wpforms-template-select' ) ) {
|
||||
return app.slugToUTMContent( $el.data( 'slug' ) );
|
||||
}
|
||||
|
||||
// UTM content for Addons (sidebar).
|
||||
if ( $el.hasClass( 'wpforms-panel-sidebar-section' ) ) {
|
||||
return app.slugToUTMContent( $el.data( 'slug' ) ) + ' Addon';
|
||||
}
|
||||
|
||||
// UTM content by default with fallback `data-name`.
|
||||
return $el.data( 'utm-content' ) || $el.data( 'name' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert slug to UTM content.
|
||||
*
|
||||
* @since 1.6.9
|
||||
*
|
||||
* @param {string} slug Slug.
|
||||
*
|
||||
* @return {string} UTM content string.
|
||||
*/
|
||||
slugToUTMContent( slug ) {
|
||||
if ( ! slug ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return slug.toString()
|
||||
|
||||
// Replace all non-alphanumeric characters with space.
|
||||
.replace( /[^a-z\d ]/gi, ' ' )
|
||||
|
||||
// Uppercase each word.
|
||||
.replace( /\b[a-z]/g, function( char ) {
|
||||
return char.toUpperCase();
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get upgrade URL according to the UTM content and license type.
|
||||
*
|
||||
* @since 1.6.9
|
||||
*
|
||||
* @param {string} utmContent UTM content.
|
||||
* @param {string} type Feature license type: pro or elite.
|
||||
*
|
||||
* @return {string} Upgrade URL.
|
||||
*/
|
||||
getUpgradeURL( utmContent, type ) {
|
||||
let baseURL = wpforms_education.upgrade[ type ].url;
|
||||
|
||||
if ( utmContent.toLowerCase().indexOf( 'template' ) > -1 ) {
|
||||
baseURL = wpforms_education.upgrade[ type ].url_template;
|
||||
}
|
||||
|
||||
if ( utmContent.toLowerCase().indexOf( 'themes' ) > -1 ) {
|
||||
baseURL = wpforms_education.upgrade[ type ].url_themes;
|
||||
}
|
||||
|
||||
// Test if the base URL already contains `?`.
|
||||
let appendChar = /(\?)/.test( baseURL ) ? '&' : '?';
|
||||
|
||||
// If the upgrade link is changed by partners, appendChar has to be encoded.
|
||||
if ( baseURL.indexOf( 'https://wpforms.com' ) === -1 ) {
|
||||
appendChar = encodeURIComponent( appendChar );
|
||||
}
|
||||
|
||||
return baseURL + appendChar + 'utm_content=' + encodeURIComponent( utmContent.trim() );
|
||||
},
|
||||
|
||||
/**
|
||||
* Upgrade modal second state.
|
||||
*
|
||||
* @since 1.6.6
|
||||
*
|
||||
* @param {string} type Feature license type: pro or elite.
|
||||
*/
|
||||
upgradeModalThankYou: ( type ) => {
|
||||
$.alert( {
|
||||
title: wpforms_education.thanks_for_interest,
|
||||
content: wpforms_education.upgrade[ type ].modal,
|
||||
icon: 'fa fa-info-circle',
|
||||
type: 'blue',
|
||||
boxWidth: '565px',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_education.ok,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get spinner markup.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @return {string} Spinner markup.
|
||||
*/
|
||||
getSpinner: () => {
|
||||
return spinner;
|
||||
},
|
||||
|
||||
/**
|
||||
* Addon activate modal.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @param {jQuery} $button jQuery button element.
|
||||
*/
|
||||
activateModal( $button ) {
|
||||
const feature = $button.data( 'name' ),
|
||||
message = $button.data( 'message' );
|
||||
|
||||
const canActivateAddons = wpforms_education.can_activate_addons;
|
||||
|
||||
$.alert( {
|
||||
title: false,
|
||||
content: message ? message : wpforms_education.activate_prompt.replace( /%name%/g, feature ),
|
||||
icon: 'fa fa-info-circle',
|
||||
type: 'blue',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_education.activate_confirm,
|
||||
btnClass: 'btn-confirm' + ( ! canActivateAddons ? ' hidden' : '' ),
|
||||
keys: [ 'enter' ],
|
||||
isHidden: ! canActivateAddons,
|
||||
action() {
|
||||
this.$$confirm
|
||||
.prop( 'disabled', true )
|
||||
.html( spinner + wpforms_education.activating );
|
||||
|
||||
this.$$cancel
|
||||
.prop( 'disabled', true );
|
||||
|
||||
app.activateAddon( $button, this );
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_education.cancel,
|
||||
action() {
|
||||
/**
|
||||
* Trigger event when modal is closed.
|
||||
* This event is used to handle any custom logic when the modal is closed.
|
||||
*
|
||||
* @since 1.9.6.1
|
||||
*
|
||||
* @param {jQuery} $button jQuery button element.
|
||||
*/
|
||||
$( document ).trigger( 'wpformsEducationModalClose', $button );
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Activate addon via AJAX.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @param {jQuery} $button jQuery button element.
|
||||
* @param {Object} previousModal Previous modal instance.
|
||||
*/
|
||||
activateAddon( $button, previousModal ) {
|
||||
const path = $button.data( 'path' ),
|
||||
pluginType = $button.data( 'type' ),
|
||||
nonce = $button.data( 'nonce' ),
|
||||
hideOnSuccess = $button.data( 'hide-on-success' );
|
||||
|
||||
$.post(
|
||||
wpforms_education.ajax_url,
|
||||
{
|
||||
action: 'wpforms_activate_addon',
|
||||
nonce,
|
||||
plugin: path,
|
||||
type: pluginType,
|
||||
},
|
||||
function( res ) {
|
||||
previousModal.close();
|
||||
|
||||
if ( res.success ) {
|
||||
if ( hideOnSuccess ) {
|
||||
$button.hide();
|
||||
}
|
||||
|
||||
app.saveModal( pluginType === 'plugin' ? wpforms_education.plugin_activated : wpforms_education.addon_activated );
|
||||
} else {
|
||||
$.alert( {
|
||||
title: false,
|
||||
content: res.data,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_education.close,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Ask user if they would like to save form and refresh form builder.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @param {string} title Modal title.
|
||||
* @param {string|boolean} content Modal content.
|
||||
* @param {Object} args Additional arguments.
|
||||
*/
|
||||
saveModal( title, content = false, args = undefined ) {
|
||||
title = title || wpforms_education.addon_activated;
|
||||
content = content || wpforms_education.save_prompt;
|
||||
|
||||
$.alert( {
|
||||
title: title.replace( /\.$/, '' ), // Remove a dot in the title end.
|
||||
content,
|
||||
icon: 'fa fa-check-circle',
|
||||
type: 'green',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: args?.saveConfirm || wpforms_education.save_confirm,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action() {
|
||||
if ( typeof WPFormsBuilder === 'undefined' ) {
|
||||
location.reload();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.$$confirm
|
||||
.prop( 'disabled', true )
|
||||
.html( spinner + wpforms_education.saving );
|
||||
|
||||
this.$$cancel
|
||||
.prop( 'disabled', true );
|
||||
|
||||
if ( WPFormsBuilder.formIsSaved() ) {
|
||||
app.redirect( args?.redirectUrl );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const saveForm = WPFormsBuilder.formSave( false );
|
||||
|
||||
if ( ! saveForm ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
saveForm.done( function() {
|
||||
app.redirect( args?.redirectUrl );
|
||||
} );
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_education.close,
|
||||
action() {
|
||||
/**
|
||||
* Triggers an event to notify that the education save modal has been closed.
|
||||
*
|
||||
* @since 1.9.6.1
|
||||
*/
|
||||
$( document ).trigger( 'wpformsEducationSaveModalClose' );
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Redirect to URL or reload the page.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*
|
||||
* @param {string} url Redirect URL.
|
||||
*/
|
||||
redirect( url ) {
|
||||
if ( url ) {
|
||||
location.href = url;
|
||||
} else {
|
||||
location.reload();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Addon install modal.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @param {jQuery} $button jQuery button element.
|
||||
*/
|
||||
installModal( $button ) {
|
||||
const feature = $button.data( 'name' ),
|
||||
url = $button.data( 'url' );
|
||||
|
||||
if ( ! url || '' === url ) {
|
||||
wpf.debug( `Couldn't install the ${ feature } addon: Empty install URL.` );
|
||||
return;
|
||||
}
|
||||
|
||||
const canInstallAddons = wpforms_education.can_install_addons,
|
||||
message = $button.data( 'message' );
|
||||
|
||||
$.alert( {
|
||||
title: false,
|
||||
content: message ? message : wpforms_education.install_prompt.replace( /%name%/g, feature ),
|
||||
icon: 'fa fa-info-circle',
|
||||
type: 'blue',
|
||||
boxWidth: '425px',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_education.install_confirm,
|
||||
btnClass: 'btn-confirm' + ( ! canInstallAddons ? ' hidden' : '' ),
|
||||
keys: [ 'enter' ],
|
||||
isHidden: ! canInstallAddons,
|
||||
action() {
|
||||
this.$$confirm.prop( 'disabled', true )
|
||||
.html( spinner + wpforms_education.installing );
|
||||
|
||||
this.$$cancel
|
||||
.prop( 'disabled', true );
|
||||
|
||||
app.installAddon( $button, this );
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_education.cancel,
|
||||
action() {
|
||||
$( document ).trigger( 'wpformsEducationModalClose', $button );
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Inform customer about incompatible addon modal.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*
|
||||
* @param {jQuery} $button jQuery button element.
|
||||
*/
|
||||
incompatibleModal( $button ) {
|
||||
const title = wpforms_education.addon_incompatible.title;
|
||||
const content = $button.data( 'message' ) || wpforms_education.addon_error;
|
||||
|
||||
$.alert( {
|
||||
title,
|
||||
content,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_education.addon_incompatible.button_text,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action() {
|
||||
if ( typeof WPFormsBuilder === 'undefined' ) {
|
||||
app.redirect( wpforms_education.addon_incompatible.button_url );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
this.$$confirm
|
||||
.prop( 'disabled', true )
|
||||
.html( spinner + this.$$confirm.text() );
|
||||
|
||||
this.$$cancel
|
||||
.prop( 'disabled', true );
|
||||
|
||||
if ( WPFormsBuilder.formIsSaved() ) {
|
||||
app.redirect( wpforms_education.addon_incompatible.button_url );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const saveForm = WPFormsBuilder.formSave( false );
|
||||
|
||||
if ( ! saveForm ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
saveForm.done( function() {
|
||||
app.redirect( wpforms_education.addon_incompatible.button_url );
|
||||
} );
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_education.cancel,
|
||||
action() {
|
||||
$( document ).trigger( 'wpformsEducationModalClose', $button );
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Install addon via AJAX.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @param {jQuery} $button Button object.
|
||||
* @param {Object} previousModal Previous modal instance.
|
||||
*/
|
||||
installAddon( $button, previousModal ) {
|
||||
const url = $button.data( 'url' ),
|
||||
pluginType = $button.data( 'type' ),
|
||||
nonce = $button.data( 'nonce' ),
|
||||
hideOnSuccess = $button.data( 'hide-on-success' );
|
||||
|
||||
$.post(
|
||||
wpforms_education.ajax_url,
|
||||
{
|
||||
action: 'wpforms_install_addon',
|
||||
nonce,
|
||||
plugin: url,
|
||||
type: pluginType,
|
||||
},
|
||||
function( res ) {
|
||||
previousModal.close();
|
||||
|
||||
if ( res.success ) {
|
||||
if ( hideOnSuccess ) {
|
||||
$button.hide();
|
||||
}
|
||||
|
||||
app.saveModal( res.data.msg );
|
||||
} else {
|
||||
let message = res.data;
|
||||
|
||||
if ( 'object' === typeof res.data ) {
|
||||
message = wpforms_education.addon_error;
|
||||
}
|
||||
|
||||
$.alert( {
|
||||
title: false,
|
||||
content: message,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_education.close,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get upgrade modal width.
|
||||
*
|
||||
* @since 1.7.3
|
||||
*
|
||||
* @param {boolean} isVideoModal Upgrade a modal type (with video or not).
|
||||
*
|
||||
* @return {string} Modal width in pixels.
|
||||
*/
|
||||
getUpgradeModalWidth( isVideoModal ) {
|
||||
const windowWidth = $( window ).width();
|
||||
|
||||
if ( windowWidth <= 300 ) {
|
||||
return '250px';
|
||||
}
|
||||
|
||||
if ( windowWidth <= 750 ) {
|
||||
return '350px';
|
||||
}
|
||||
|
||||
if ( ! isVideoModal || windowWidth <= 1024 ) {
|
||||
return '550px';
|
||||
}
|
||||
|
||||
return windowWidth > 1070 ? '1040px' : '994px';
|
||||
},
|
||||
|
||||
/**
|
||||
* Error modal.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @param {string} title Modal title.
|
||||
* @param {string} content Modal content.
|
||||
*/
|
||||
errorModal( title, content ) {
|
||||
$.alert( {
|
||||
title: title || false,
|
||||
content,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_education.close,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
WPFormsEducation.core.init();
|
||||
+1
File diff suppressed because one or more lines are too long
+436
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,476 @@
|
||||
/* global wpforms_edit_post_education */
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
/**
|
||||
* WPForms Edit Post Education function.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line no-var, no-unused-vars
|
||||
var WPFormsEditPostEducation = window.WPFormsEditPostEducation || ( function( document, window, $ ) {
|
||||
// The identifiers for the Redux stores.
|
||||
const coreEditSite = 'core/edit-site',
|
||||
coreEditor = 'core/editor',
|
||||
coreBlockEditor = 'core/block-editor',
|
||||
coreNotices = 'core/notices',
|
||||
|
||||
// Heading block name.
|
||||
coreHeading = 'core/heading';
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Determine if the notice was shown before.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
isNoticeVisible: false,
|
||||
|
||||
/**
|
||||
* Identifier for the plugin and notice.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*/
|
||||
pluginId: 'wpforms-edit-post-product-education-guide',
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
init() {
|
||||
$( window ).on( 'load', function() {
|
||||
// In the case of jQuery 3.+, we need to wait for a ready event first.
|
||||
if ( typeof $.ready.then === 'function' ) {
|
||||
$.ready.then( app.load );
|
||||
} else {
|
||||
app.load();
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Page load.
|
||||
*
|
||||
* @since 1.8.1
|
||||
* @since 1.9.5 Added compatibility for the Site Editor.
|
||||
*/
|
||||
load() {
|
||||
if ( ! app.isGutenbergEditor() ) {
|
||||
app.maybeShowClassicNotice();
|
||||
app.bindClassicEvents();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
app.maybeShowGutenbergNotice();
|
||||
|
||||
// "core/edit-site" store available only in the Site Editor.
|
||||
if ( !! wp.data.select( coreEditSite ) ) {
|
||||
app.subscribeForSiteEditor();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
app.subscribeForBlockEditor();
|
||||
},
|
||||
|
||||
/**
|
||||
* This method listens for changes in the WordPress data store and performs the following actions:
|
||||
* - Monitors the editor title and focus mode to detect changes.
|
||||
* - Dismisses a custom notice if the focus mode is disabled and the notice is visible.
|
||||
* - Shows a custom Gutenberg notice if the title or focus mode changes.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*/
|
||||
subscribeForSiteEditor() {
|
||||
// Store the initial editor title and focus mode state.
|
||||
let prevTitle = app.getEditorTitle();
|
||||
let prevFocusMode = null;
|
||||
const { subscribe, select, dispatch } = wp.data;
|
||||
|
||||
// Listen for changes in the WordPress data store.
|
||||
subscribe( () => {
|
||||
// Fetch the current editor mode setting.
|
||||
// If true - Site Editor canvas is opened, and you can edit something.
|
||||
// If false - you should see the sidebar with navigation and preview
|
||||
// with selected template or page.
|
||||
const { focusMode } = select( coreEditor ).getEditorSettings();
|
||||
|
||||
// If focus mode is disabled and a notice is visible, remove the notice.
|
||||
// This is essential because user can switch pages / templates
|
||||
// without a page-reload.
|
||||
if ( ! focusMode && app.isNoticeVisible ) {
|
||||
app.isNoticeVisible = false;
|
||||
prevFocusMode = focusMode;
|
||||
|
||||
dispatch( coreNotices ).removeNotice( app.pluginId );
|
||||
}
|
||||
|
||||
const title = app.getEditorTitle();
|
||||
|
||||
// If neither the title nor the focus mode has changed, do nothing.
|
||||
if ( prevTitle === title && prevFocusMode === focusMode ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the previous title and focus mode values for the next subscription cycle.
|
||||
prevTitle = title;
|
||||
prevFocusMode = focusMode;
|
||||
|
||||
// Show a custom Gutenberg notice if conditions are met.
|
||||
app.maybeShowGutenbergNotice();
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Subscribes to changes in the WordPress block editor and monitors the editor's title.
|
||||
* When the title changes, it triggers a process to potentially display a Gutenberg notice.
|
||||
* The subscription is automatically stopped if the notice becomes visible.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*/
|
||||
subscribeForBlockEditor() {
|
||||
let prevTitle = app.getEditorTitle();
|
||||
const { subscribe } = wp.data;
|
||||
|
||||
// Subscribe to WordPress data changes.
|
||||
const unsubscribe = subscribe( () => {
|
||||
const title = app.getEditorTitle();
|
||||
|
||||
// Check if the title has changed since the previous value.
|
||||
if ( prevTitle === title ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the previous title to the current title.
|
||||
prevTitle = title;
|
||||
|
||||
app.maybeShowGutenbergNotice();
|
||||
|
||||
// If the notice is visible, stop the WordPress data subscription.
|
||||
if ( app.isNoticeVisible ) {
|
||||
unsubscribe();
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the title of the post currently being edited. If in the Site Editor,
|
||||
* it attempts to fetch the title from the topmost heading block. Otherwise, it
|
||||
* retrieves the title attribute of the edited post.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*
|
||||
* @return {string} The post title or an empty string if no title is found.
|
||||
*/
|
||||
getEditorTitle() {
|
||||
const { select } = wp.data;
|
||||
|
||||
// Retrieve the title for Post Editor.
|
||||
if ( ! select( coreEditSite ) ) {
|
||||
return select( coreEditor ).getEditedPostAttribute( 'title' );
|
||||
}
|
||||
|
||||
if ( app.isEditPostFSE() ) {
|
||||
return app.getPostTitle();
|
||||
}
|
||||
|
||||
return app.getTopmostHeadingTitle();
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the content of the first heading block.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*
|
||||
* @return {string} The topmost heading content or null if not found.
|
||||
*/
|
||||
getTopmostHeadingTitle() {
|
||||
const { select } = wp.data;
|
||||
|
||||
const headings = select( coreBlockEditor ).getBlocksByName( coreHeading );
|
||||
|
||||
if ( ! headings.length ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const headingBlock = select( coreBlockEditor ).getBlock( headings[ 0 ] );
|
||||
|
||||
return headingBlock?.attributes?.content?.text ?? '';
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if the current editing context is for a post type in the Full Site Editor (FSE).
|
||||
*
|
||||
* @since 1.9.5
|
||||
*
|
||||
* @return {boolean} True if the current context represents a post type in the FSE, otherwise false.
|
||||
*/
|
||||
isEditPostFSE() {
|
||||
const { select } = wp.data;
|
||||
const { context } = select( coreEditSite ).getPage();
|
||||
|
||||
return !! context?.postType;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the title of a post based on its type and ID from the current editing context.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*
|
||||
* @return {string} The title of the post.
|
||||
*/
|
||||
getPostTitle() {
|
||||
const { select } = wp.data;
|
||||
const { context } = select( coreEditSite ).getPage();
|
||||
|
||||
// Use `getEditedEntityRecord` instead of `getEntityRecord`
|
||||
// to fetch the live, updated data for the post being edited.
|
||||
const { title = '' } = select( 'core' ).getEditedEntityRecord(
|
||||
'postType',
|
||||
context.postType,
|
||||
context.postId
|
||||
) || {};
|
||||
|
||||
return title;
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events for Classic Editor.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
bindClassicEvents() {
|
||||
const $document = $( document );
|
||||
|
||||
if ( ! app.isNoticeVisible ) {
|
||||
$document.on( 'input', '#title', _.debounce( app.maybeShowClassicNotice, 1000 ) );
|
||||
}
|
||||
|
||||
$document.on( 'click', '.wpforms-edit-post-education-notice-close', app.closeNotice );
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine if the editor is Gutenberg.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @return {boolean} True if the editor is Gutenberg.
|
||||
*/
|
||||
isGutenbergEditor() {
|
||||
return typeof wp !== 'undefined' && typeof wp.blocks !== 'undefined';
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a notice for Gutenberg.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
showGutenbergNotice() {
|
||||
wp.data.dispatch( coreNotices ).createInfoNotice(
|
||||
wpforms_edit_post_education.gutenberg_notice.template,
|
||||
app.getGutenbergNoticeSettings()
|
||||
);
|
||||
|
||||
// The notice component doesn't have a way to add HTML id or class to the notice.
|
||||
// Also, the notice became visible with a delay on old Gutenberg versions.
|
||||
const hasNotice = setInterval( function() {
|
||||
const noticeBody = $( '.wpforms-edit-post-education-notice-body' );
|
||||
if ( ! noticeBody.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $notice = noticeBody.closest( '.components-notice' );
|
||||
$notice.addClass( 'wpforms-edit-post-education-notice' );
|
||||
$notice.find( '.is-secondary, .is-link' ).removeClass( 'is-secondary' ).removeClass( 'is-link' ).addClass( 'is-primary' );
|
||||
|
||||
// We can't use onDismiss callback as it was introduced in WordPress 6.0 only.
|
||||
const dismissButton = $notice.find( '.components-notice__dismiss' );
|
||||
if ( dismissButton ) {
|
||||
dismissButton.on( 'click', function() {
|
||||
app.updateUserMeta();
|
||||
} );
|
||||
}
|
||||
|
||||
clearInterval( hasNotice );
|
||||
}, 100 );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get settings for the Gutenberg notice.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @return {Object} Notice settings.
|
||||
*/
|
||||
getGutenbergNoticeSettings() {
|
||||
const noticeSettings = {
|
||||
id: app.pluginId,
|
||||
isDismissible: true,
|
||||
HTML: true,
|
||||
__unstableHTML: true,
|
||||
actions: [
|
||||
{
|
||||
className: 'wpforms-edit-post-education-notice-guide-button',
|
||||
variant: 'primary',
|
||||
label: wpforms_edit_post_education.gutenberg_notice.button,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
if ( ! wpforms_edit_post_education.gutenberg_guide ) {
|
||||
noticeSettings.actions[ 0 ].url = wpforms_edit_post_education.gutenberg_notice.url;
|
||||
|
||||
return noticeSettings;
|
||||
}
|
||||
|
||||
const { Guide } = wp.components,
|
||||
{ useState } = wp.element,
|
||||
{ registerPlugin, unregisterPlugin } = wp.plugins;
|
||||
|
||||
const GutenbergTutorial = function() {
|
||||
const [ isOpen, setIsOpen ] = useState( true );
|
||||
|
||||
if ( ! isOpen ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line react/react-in-jsx-scope
|
||||
<Guide
|
||||
className="edit-post-welcome-guide"
|
||||
onFinish={ () => {
|
||||
unregisterPlugin( app.pluginId );
|
||||
setIsOpen( false );
|
||||
} }
|
||||
pages={ app.getGuidePages() }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
noticeSettings.actions[ 0 ].onClick = () => registerPlugin( app.pluginId, { render: GutenbergTutorial } );
|
||||
|
||||
return noticeSettings;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get Guide pages in proper format.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @return {Array} Guide Pages.
|
||||
*/
|
||||
getGuidePages() {
|
||||
const pages = [];
|
||||
|
||||
wpforms_edit_post_education.gutenberg_guide.forEach( function( page ) {
|
||||
pages.push(
|
||||
{
|
||||
/* eslint-disable react/react-in-jsx-scope */
|
||||
content: (
|
||||
<>
|
||||
<h1 className="edit-post-welcome-guide__heading">{ page.title }</h1>
|
||||
<p className="edit-post-welcome-guide__text">{ page.content }</p>
|
||||
</>
|
||||
),
|
||||
image: <img className="edit-post-welcome-guide__image" src={ page.image } alt={ page.title } />,
|
||||
/* eslint-enable react/react-in-jsx-scope */
|
||||
}
|
||||
);
|
||||
} );
|
||||
|
||||
return pages;
|
||||
},
|
||||
|
||||
/**
|
||||
* Show notice if the page title matches some keywords for Classic Editor.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
maybeShowClassicNotice() {
|
||||
if ( app.isNoticeVisible ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( app.isTitleMatchKeywords( $( '#title' ).val() ) ) {
|
||||
app.isNoticeVisible = true;
|
||||
|
||||
$( '.wpforms-edit-post-education-notice' ).removeClass( 'wpforms-hidden' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Show notice if the page title matches some keywords for Gutenberg Editor.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
maybeShowGutenbergNotice() {
|
||||
if ( app.isNoticeVisible ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const title = app.getEditorTitle();
|
||||
|
||||
if ( app.isTitleMatchKeywords( title ) ) {
|
||||
app.isNoticeVisible = true;
|
||||
|
||||
app.showGutenbergNotice();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine if the title matches keywords.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @param {string} titleValue Page title value.
|
||||
*
|
||||
* @return {boolean} True if the title matches some keywords.
|
||||
*/
|
||||
isTitleMatchKeywords( titleValue ) {
|
||||
const expectedTitleRegex = new RegExp( /\b(contact|form)\b/i );
|
||||
|
||||
return expectedTitleRegex.test( titleValue );
|
||||
},
|
||||
|
||||
/**
|
||||
* Close a notice.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
closeNotice() {
|
||||
$( this ).closest( '.wpforms-edit-post-education-notice' ).remove();
|
||||
|
||||
app.updateUserMeta();
|
||||
},
|
||||
|
||||
/**
|
||||
* Update user meta and don't show the notice next time.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
updateUserMeta() {
|
||||
$.post(
|
||||
wpforms_edit_post_education.ajax_url,
|
||||
{
|
||||
action: 'wpforms_education_dismiss',
|
||||
nonce: wpforms_edit_post_education.education_nonce,
|
||||
section: 'edit-post-notice',
|
||||
}
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
WPFormsEditPostEducation.init();
|
||||
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* PDF Education.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*
|
||||
* @param {Window} window The global window object.
|
||||
* @param {jQuery} $ The jQuery object.
|
||||
*/
|
||||
( function( window, $ ) {
|
||||
const app = {
|
||||
/**
|
||||
* The whole popup element.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*
|
||||
* @type {jQuery}
|
||||
*/
|
||||
$popup: null,
|
||||
|
||||
/**
|
||||
* The builder element.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*
|
||||
* @type {jQuery}
|
||||
*/
|
||||
$builder: null,
|
||||
|
||||
/**
|
||||
* The close button element inside the popup. Closes popup.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*
|
||||
* @type {jQuery}
|
||||
*/
|
||||
$close: null,
|
||||
|
||||
/**
|
||||
* The button element inside the popup. Triggers the PDF panel.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*
|
||||
* @type {jQuery}
|
||||
*/
|
||||
$switchButton: null,
|
||||
|
||||
/**
|
||||
* The notification section element.
|
||||
* This is what a user sees when clicking on Builder > Settings > Notifications.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*
|
||||
* @type {jQuery}
|
||||
*/
|
||||
$notifications: null,
|
||||
|
||||
/**
|
||||
* The PDF panel element.
|
||||
* This is what a user sees when clicking on Builder > Settings > PDF.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*
|
||||
* @type {jQuery}
|
||||
*/
|
||||
$pdfPanel: null,
|
||||
|
||||
/**
|
||||
* Initializes the app.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*/
|
||||
ready() {
|
||||
app.$popup = $( '#wpforms-pdf-popup' );
|
||||
app.$close = app.$popup.find( '.close-popup' );
|
||||
app.$switchButton = app.$popup.find( 'button.education-modal[data-target="wpforms-pdf"]' );
|
||||
app.$notifications = $( '.wpforms-panel-content-section.wpforms-panel-content-section-notifications' );
|
||||
app.$builder = $( '#wpforms-builder' );
|
||||
app.$pdfPanel = $( '.wpforms-panel-sidebar-section.wpforms-panel-sidebar-section-pdf' );
|
||||
|
||||
app.run();
|
||||
},
|
||||
/**
|
||||
* Runs the app.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*/
|
||||
run() {
|
||||
/*
|
||||
* User clicked on one of the subsections in Builder > Settings.
|
||||
*/
|
||||
app.$builder.on( 'wpformsPanelSectionSwitch', function( e, section ) {
|
||||
if ( section === 'default' || ! section ) {
|
||||
return;
|
||||
}
|
||||
|
||||
app.$popup.toggle( section === 'notifications' );
|
||||
} );
|
||||
|
||||
/*
|
||||
* User clicked on the left dark sidebar in Builder.
|
||||
*/
|
||||
app.$builder.on( 'wpformsPanelSwitched', () => {
|
||||
app.$popup.toggle( app.$notifications.is( ':visible' ) );
|
||||
} );
|
||||
|
||||
/*
|
||||
* User clicked on the 'Try it Out' button.
|
||||
*/
|
||||
app.$switchButton.on( 'click', function( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
app.$pdfPanel.click();
|
||||
} );
|
||||
},
|
||||
};
|
||||
|
||||
app.init();
|
||||
}( window, jQuery ) );
|
||||
+1
@@ -0,0 +1 @@
|
||||
(n=>{let i={$popup:null,$builder:null,$close:null,$switchButton:null,$notifications:null,$pdfPanel:null,init(){n(i.ready)},ready(){i.$popup=n("#wpforms-pdf-popup"),i.$close=i.$popup.find(".close-popup"),i.$switchButton=i.$popup.find('button.education-modal[data-target="wpforms-pdf"]'),i.$notifications=n(".wpforms-panel-content-section.wpforms-panel-content-section-notifications"),i.$builder=n("#wpforms-builder"),i.$pdfPanel=n(".wpforms-panel-sidebar-section.wpforms-panel-sidebar-section-pdf"),i.run()},run(){i.$builder.on("wpformsPanelSectionSwitch",function(n,o){"default"!==o&&o&&i.$popup.toggle("notifications"===o)}),i.$builder.on("wpformsPanelSwitched",()=>{i.$popup.toggle(i.$notifications.is(":visible"))}),i.$switchButton.on("click",function(n){n.preventDefault(),i.$pdfPanel.click()})}};i.init()})((window,jQuery));
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
/* eslint-disable camelcase */
|
||||
/* global ajaxurl, wpforms_education_pointers_payment */
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
/**
|
||||
* Module for handling education pointers related to payments in WPForms.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
var WPFormsPointersPayment = window.WPFormsPointersPayment || ( function( document, window, $, l10n ) {
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const el = {};
|
||||
|
||||
/**
|
||||
* Runtime variables.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const vars = {
|
||||
/**
|
||||
* Unique ID for the pointer.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
pointerId: l10n.pointer,
|
||||
|
||||
/**
|
||||
* Cryptographic token for validating authorized Ajax data exchange.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
nonce: l10n.nonce,
|
||||
};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
ready() {
|
||||
app.setup();
|
||||
app.bindEvents();
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup. Prepare some variables.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
setup() {
|
||||
// Cache DOM elements.
|
||||
el.$document = $( document );
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
bindEvents() {
|
||||
el.$document.on( 'click', '#toplevel_page_wpforms-overview [href$="-payments"], #wpforms-education-pointers-payments', app.handleOnClick );
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for clicking on the action link.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*
|
||||
* @param {Object} event An event which takes place in the DOM.
|
||||
*/
|
||||
handleOnClick( event ) {
|
||||
// Prevent the default action.
|
||||
event.preventDefault();
|
||||
|
||||
const $this = $( this );
|
||||
|
||||
// Get the href attribute.
|
||||
const href = $this.attr( 'href' );
|
||||
|
||||
// Return early if href is missing.
|
||||
if ( ! href ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Hide the pointer before redirecting.
|
||||
$this.closest( '.wp-pointer-content' ).parent().hide();
|
||||
|
||||
// Send AJAX request.
|
||||
$.post(
|
||||
ajaxurl,
|
||||
{
|
||||
pointer_id: vars.pointerId,
|
||||
_ajax_nonce: vars.nonce,
|
||||
action: 'wpforms_education_pointers_engagement',
|
||||
}
|
||||
).done( function() {
|
||||
window.location.href = href;
|
||||
} );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery, wpforms_education_pointers_payment ) );
|
||||
|
||||
// Initialize.
|
||||
WPFormsPointersPayment.init();
|
||||
Vendored
Executable
+1
@@ -0,0 +1 @@
|
||||
var WPFormsPointersPayment=window.WPFormsPointersPayment||((e,t,o,n)=>{let i={},r={pointerId:n.pointer,nonce:n.nonce},a={init(){o(a.ready)},ready(){a.setup(),a.bindEvents()},setup(){i.$document=o(e)},bindEvents(){i.$document.on("click",'#toplevel_page_wpforms-overview [href$="-payments"], #wpforms-education-pointers-payments',a.handleOnClick)},handleOnClick(e){e.preventDefault();e=o(this);let n=e.attr("href");n&&(e.closest(".wp-pointer-content").parent().hide(),o.post(ajaxurl,{pointer_id:r.pointerId,_ajax_nonce:r.nonce,action:"wpforms_education_pointers_engagement"}).done(function(){t.location.href=n}))}};return a})(document,window,jQuery,wpforms_education_pointers_payment);WPFormsPointersPayment.init();
|
||||
@@ -0,0 +1,515 @@
|
||||
/* global Choices, wpforms_admin_email_settings */
|
||||
/**
|
||||
* Script for manipulating DOM events in the "Email" settings page.
|
||||
* This script will be accessible in the "WPForms" → "Settings" → "Email" page.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*/
|
||||
|
||||
const WPFormsEmailSettings = window.WPFormsEmailSettings || ( function( document, window, $, l10n ) {
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const el = {};
|
||||
|
||||
/**
|
||||
* Runtime variables.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const vars = {
|
||||
cache: {
|
||||
appearance: {
|
||||
light: '#email-appearance-light',
|
||||
},
|
||||
colors: {
|
||||
light: {
|
||||
background: [
|
||||
'#wpforms-setting-email-background-color',
|
||||
'#wpforms-setting-email-color-scheme-email_background_color',
|
||||
],
|
||||
text: '#wpforms-setting-email-color-scheme-email_text_color',
|
||||
},
|
||||
dark: {
|
||||
background: [
|
||||
'#wpforms-setting-email-background-color-dark',
|
||||
'#wpforms-setting-email-color-scheme-dark-email_background_color_dark',
|
||||
],
|
||||
text: '#wpforms-setting-email-color-scheme-dark-email_text_color_dark',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Generic CSS class names for applying visual changes.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
classNames: {
|
||||
hide: 'wpforms-hide',
|
||||
appearance: 'email-appearance-mode-toggle',
|
||||
legacyTemplate: 'legacy-template',
|
||||
hideForPlainText: 'hide-for-template-none',
|
||||
headerImage: 'wpforms-email-header-image',
|
||||
colorScheme: 'email-color-scheme',
|
||||
typography: 'email-typography',
|
||||
noticeWarning: 'notice-warning',
|
||||
noticeLegacy: 'wpforms-email-legacy-notice',
|
||||
settingsRow: 'wpforms-setting-row',
|
||||
settingField: 'wpforms-setting-field',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*/
|
||||
ready() {
|
||||
app.setup();
|
||||
app.bindEvents();
|
||||
app.relocateImageSize();
|
||||
app.handleOnContrastChange();
|
||||
app.handleOnChangeBackgroundColor();
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup. Prepare some variables.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*/
|
||||
setup() {
|
||||
// Cache DOM elements.
|
||||
el.$wrapper = $( '.wpforms-admin-settings-email' );
|
||||
el.$appearance = $( `.${ vars.classNames.appearance }` );
|
||||
el.$colorScheme = $( `.${ vars.classNames.colorScheme }` );
|
||||
el.$typography = $( `.${ vars.classNames.typography }` );
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*/
|
||||
bindEvents() {
|
||||
el.$wrapper
|
||||
.on( 'change', '.wpforms-email-template input[type="radio"]', app.handleOnUpdateTemplate )
|
||||
.on( 'change', '.wpforms-email-header-image input', app.handleOnChangeHeaderImage )
|
||||
.on( 'click', '.wpforms-setting-remove-image', app.handleOnRemoveHeaderImage )
|
||||
.on( 'change', '.has-preview-changes :input', app.handleOnPreviewChanges )
|
||||
.on( 'change', '.email-appearance-mode-toggle input', app.handleOnAppearanceModeToggle )
|
||||
// Selectors for the following events are specified by matching the ID attribute by design to ensure both appearance modes are covered.
|
||||
.on( 'change', '[id*="email-background-color"], [id*="email_background_color"]', app.handleOnChangeBackgroundColor )
|
||||
.on( 'change', '[id*="email_body_color"], [id*="email_text_color"]', app.handleOnContrastChange );
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for template change.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*
|
||||
* @param {Object} event An event which takes place in the DOM.
|
||||
*/
|
||||
handleOnUpdateTemplate( event ) {
|
||||
// Get the selected value from the event.
|
||||
const selected = $( event.currentTarget ).val();
|
||||
|
||||
// Find relevant elements in the wrapper.
|
||||
const $hideForNone = el.$wrapper.find( `.${ vars.classNames.hideForPlainText }` );
|
||||
const $imageSizeChoices = el.$wrapper.find( `.${ vars.classNames.headerImage } .choices` );
|
||||
const $backgroundControl = el.$wrapper.find( '.email-background-color' );
|
||||
const $legacyNotice = el.$wrapper.find( `.${ vars.classNames.noticeLegacy }` );
|
||||
const $educationModal = el.$wrapper.find( '.education-modal' );
|
||||
|
||||
// Check if it's a Pro template.
|
||||
const isPro = $educationModal.length === 0;
|
||||
|
||||
// Check if the selected value is 'none' or 'default'.
|
||||
const isNone = selected === 'none';
|
||||
const isDefault = selected === 'default';
|
||||
|
||||
// Toggle image size choices based on the selected value.
|
||||
$imageSizeChoices.each( ( i, elm ) => {
|
||||
const $this = $( elm );
|
||||
const hasImage = $this.closest( `.${ vars.classNames.settingField }` ).find( 'img' ).length;
|
||||
$this.toggle( ! isDefault && !! hasImage );
|
||||
} );
|
||||
|
||||
// Toggle visibility for elements based on conditions.
|
||||
$hideForNone.toggle( ! isNone );
|
||||
$legacyNotice.toggle( isDefault );
|
||||
$backgroundControl.toggle( ( isDefault || ! isPro ) && ! isNone );
|
||||
|
||||
// Toggle the light mode radio button based on the selected value.
|
||||
if ( isDefault ) {
|
||||
el.$appearance.find( vars.cache.appearance.light ).trigger( 'click' );
|
||||
}
|
||||
|
||||
// Cache the class name for the legacy template.
|
||||
const { legacyTemplate: legacyTemplateClassName } = vars.classNames;
|
||||
|
||||
// Toggle classes based on the selected value.
|
||||
el.$appearance.toggleClass( legacyTemplateClassName, isDefault );
|
||||
el.$colorScheme.toggleClass( legacyTemplateClassName, isDefault );
|
||||
el.$typography.toggleClass( legacyTemplateClassName, isDefault );
|
||||
|
||||
// Update the background color.
|
||||
app.handleOnChangeBackgroundColor();
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for "Upload Image" button click.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
handleOnChangeHeaderImage() {
|
||||
// Update the background color.
|
||||
app.handleOnChangeBackgroundColor();
|
||||
|
||||
// In case the current template is "Legacy" or image tag doesn't exist, return early.
|
||||
if ( app.isLegacyTemplate() || ! $( this ).prev( 'img' ).length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Show the image size dropdown menu.
|
||||
$( this ).parent().find( '.choices' ).show();
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for "Remove Image" button click.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*/
|
||||
handleOnRemoveHeaderImage() {
|
||||
$( this ).closest( `.${ vars.classNames.settingsRow }` ).removeClass( 'has-external-image-url' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for the image size select input change.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*/
|
||||
handleOnUpdateImageSize() {
|
||||
// Get the wrapper tag.
|
||||
const $wrapper = $( this ).closest( `.${ vars.classNames.settingsRow }` );
|
||||
// Get the selected value.
|
||||
const value = $( this ).val();
|
||||
|
||||
// Remove the previous image size class.
|
||||
$wrapper.removeClass( ( index, className ) => ( className.match( /has-image-size-\w+/g ) || [] ).join( ' ' ) );
|
||||
// Add the new image size class.
|
||||
$wrapper.addClass( `has-image-size-${ value }` );
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for the background color picker input change.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
handleOnChangeBackgroundColor() {
|
||||
const [ lightBackgroundColor, darkBackgroundColor ] = app.getBackgroundColors();
|
||||
|
||||
// Sync the background color value.
|
||||
app.syncBackgroundColors( lightBackgroundColor, darkBackgroundColor );
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for the body background and text color picker input changes.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
handleOnContrastChange() {
|
||||
// Bail if the color contrast checker is not available.
|
||||
if ( ! window.WPFormsColorContrastChecker ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Define class names for elements.
|
||||
const { noticeWarning: noticeClassName, settingsRow: settingsRowClassName } = vars.classNames;
|
||||
|
||||
// Define color arrays for different elements.
|
||||
const textColors = [
|
||||
vars.cache.colors.light.text,
|
||||
vars.cache.colors.dark.text,
|
||||
];
|
||||
|
||||
textColors.forEach( ( textColor ) => {
|
||||
// Select color input elements.
|
||||
const $textColor = $( textColor );
|
||||
const $bodyColor = $textColor.parent().prev().prev().find( 'input' );
|
||||
|
||||
// Create a color contrast checker instance.
|
||||
const contrastChecker = new window.WPFormsColorContrastChecker( {
|
||||
textColor: $textColor.val(),
|
||||
bgColor: $bodyColor.val(),
|
||||
message: {
|
||||
contrastPass: '',
|
||||
contrastFail: l10n?.contrast_fail || '',
|
||||
},
|
||||
} );
|
||||
|
||||
// Check the color contrast.
|
||||
const contrastMessage = contrastChecker.checkContrast();
|
||||
|
||||
// Bail if there's no contrast message and the notice is not present.
|
||||
if ( ! contrastMessage ) {
|
||||
const $settingsRow = $textColor.closest( `.${ settingsRowClassName }` );
|
||||
$settingsRow.find( `.${ noticeClassName }` ).remove();
|
||||
return;
|
||||
}
|
||||
|
||||
// Bail if the notice is already present.
|
||||
const $settingsRow = $textColor.closest( `.${ settingsRowClassName }` );
|
||||
if ( $settingsRow.find( `.${ noticeClassName }` ).length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Append contrast notice.
|
||||
$settingsRow.append( `<div class="${ noticeClassName }"><p>${ window.wp.escapeHtml.escapeHTML( contrastMessage ) }</p></div>` );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for input changes.
|
||||
* This method is used to update the preview URL.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
handleOnPreviewChanges() {
|
||||
// Bail if the XOR encryption is not available.
|
||||
if ( ! window.WPFormsXOR ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the current input.
|
||||
const $this = $( this );
|
||||
|
||||
// Extract the 'name' attribute.
|
||||
const name = $this.attr( 'name' );
|
||||
|
||||
// Extract the ID from the 'name' attribute using a regex.
|
||||
// Explanation:
|
||||
// - /\[([^[\]]+)]/i: Match square brackets and capture the content inside.
|
||||
// - ( || [] )[1]: Use the captured content, or an empty array if not found.
|
||||
// - || name: If still not found, fallback to the original 'name'.
|
||||
// - replace(/-/g, '_'): Replace dashes with underscores in the ID.
|
||||
const id = ( ( name.match( /\[([^[\]]+)]/i ) || [] )[ 1 ] || name ).replace( /-/g, '_' );
|
||||
|
||||
// Get the current input value.
|
||||
const value = $this.val();
|
||||
|
||||
// Destructure utility functions from the wp.url object.
|
||||
const { isURL, addQueryArgs, getQueryArg } = wp.url;
|
||||
|
||||
// Query argument name.
|
||||
const queryArgName = 'wpforms_email_style_overrides';
|
||||
|
||||
// Create an XOR instance.
|
||||
const xorInstance = new window.WPFormsXOR();
|
||||
|
||||
// Filter and update the href attribute for elements with class 'wpforms-btn-preview'.
|
||||
$( '.wpforms-btn-preview' )
|
||||
.filter( ( index, elm ) => isURL( $( elm ).attr( 'href' ) ) )
|
||||
.attr( 'href', ( index, oldHref ) => {
|
||||
const existingOverrides = xorInstance.decrypt( getQueryArg( oldHref, queryArgName ) );
|
||||
const updatedOverrides = { ...existingOverrides, [ id ]: value };
|
||||
const updatedQueryString = xorInstance.encrypt( updatedOverrides );
|
||||
return addQueryArgs( oldHref, { [ queryArgName ]: updatedQueryString } );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for the appearance mode toggle.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
handleOnAppearanceModeToggle() {
|
||||
// Reference to the clicked radio button.
|
||||
const $this = $( this );
|
||||
|
||||
// Define class names for elements.
|
||||
const { hide: hideClassName, settingField: settingFieldClassName } = vars.classNames;
|
||||
|
||||
// Get the value of the selected radio button.
|
||||
const selected = $this.val();
|
||||
|
||||
// Find the closest setting field container.
|
||||
const $settingField = $this.closest( `.${ settingFieldClassName }` );
|
||||
|
||||
// Find the unselected radio button within the same setting field.
|
||||
const $unselectedInput = $settingField.find( 'input:not(:checked)' );
|
||||
|
||||
// Get the value of the unselected radio button.
|
||||
const unselected = $unselectedInput.val();
|
||||
|
||||
$( `.email-${ selected }-mode` ).removeClass( hideClassName );
|
||||
$( `.email-${ unselected }-mode` ).addClass( hideClassName );
|
||||
},
|
||||
|
||||
/**
|
||||
* Relocate image size select input for styling purposes.
|
||||
*
|
||||
* @since 1.8.5
|
||||
*/
|
||||
relocateImageSize() {
|
||||
const $imgSize = $( '.wpforms-email-header-image-size' );
|
||||
|
||||
// Bail if there is no "Remove Image" button.
|
||||
if ( $imgSize.length === 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$imgSize.each( ( index, elm ) => {
|
||||
const $this = $( elm );
|
||||
const $select = $this.find( 'select' );
|
||||
|
||||
// Bail if there is no select element.
|
||||
if ( $select.length === 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the header image element.
|
||||
const $headerImage = $this.prev();
|
||||
|
||||
// Move the select element before the "Remove Image" button.
|
||||
$headerImage.find( '.wpforms-setting-remove-image' ).before( $select.get( 0 ).outerHTML );
|
||||
|
||||
// Remove the original select element.
|
||||
$select.remove();
|
||||
|
||||
try {
|
||||
// Cache the new select input.
|
||||
const $newSelect = $headerImage.find( 'select' );
|
||||
// Add the image size class. Note that the default value is 140.
|
||||
$headerImage.addClass( `has-image-size-${ $newSelect.val() || 'medium' }` );
|
||||
// Bind the change event, and update the image size class.
|
||||
$newSelect.on( 'change', app.handleOnUpdateImageSize );
|
||||
// Initialize Choices.
|
||||
new Choices( $newSelect.get( 0 ), {
|
||||
searchEnabled: false,
|
||||
shouldSort: false,
|
||||
} );
|
||||
|
||||
// Check if it's a legacy template and adjust settings accordingly.
|
||||
if ( app.isLegacyTemplate() ) {
|
||||
el.$wrapper.find( `.${ vars.classNames.noticeLegacy }` ).show();
|
||||
$headerImage.find( '.choices' ).hide();
|
||||
}
|
||||
} catch ( e ) {
|
||||
// Handle any potential errors, but continue execution.
|
||||
// eslint-disable-next-line no-console
|
||||
console.error( 'Error during relocation:', e );
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine whether the currently selected template is the "Legacy" template.
|
||||
* Legacy template is the one that its value is 'default'.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @return {boolean} True if the current template is legacy.
|
||||
*/
|
||||
isLegacyTemplate() {
|
||||
return el.$wrapper.find( '.wpforms-setting-row-email_template input:checked' ).val() === 'default';
|
||||
},
|
||||
|
||||
/**
|
||||
* Get background colors for light and dark modes.
|
||||
*
|
||||
* This function retrieves the visible background color or falls back to the default one
|
||||
* for both light and dark modes.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @return {Array} An array containing background colors for light and dark modes.
|
||||
*/
|
||||
getBackgroundColors() {
|
||||
// Get the visible background color or the default one.
|
||||
const getVisibleBackgroundColor = ( selector, fallbackSelector ) => {
|
||||
const visibleColor = el.$wrapper.find( `${ selector }:visible` ).val();
|
||||
return visibleColor || el.$wrapper.find( fallbackSelector ).val();
|
||||
};
|
||||
|
||||
// Return an array of background colors for light and dark modes.
|
||||
return [
|
||||
getVisibleBackgroundColor( ...vars.cache.colors.light.background ),
|
||||
getVisibleBackgroundColor( ...vars.cache.colors.dark.background ),
|
||||
];
|
||||
},
|
||||
|
||||
/**
|
||||
* Sync the background color value.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} lightBackgroundColor The light background color in hex format.
|
||||
* @param {string} darkBackgroundColor The dark background color in hex format.
|
||||
*/
|
||||
syncBackgroundColors( lightBackgroundColor, darkBackgroundColor ) {
|
||||
// Bail if there is no light or dark background color.
|
||||
if ( ! lightBackgroundColor || ! darkBackgroundColor ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Define color arrays for different elements.
|
||||
const backgrounds = [
|
||||
vars.cache.colors.light.background,
|
||||
vars.cache.colors.dark.background,
|
||||
];
|
||||
|
||||
// Reflect the change in the color picker.
|
||||
for ( let i = 0; i < backgrounds.length; i++ ) {
|
||||
// Determine the color based on the loop index.
|
||||
const color = i === 0 ? lightBackgroundColor : darkBackgroundColor;
|
||||
|
||||
// Select the corresponding image element based on the loop index.
|
||||
const $img = i === 0 ? $( '#wpforms-setting-row-email-header-image' ) : $( '#wpforms-setting-row-email-header-image-dark' );
|
||||
|
||||
// Iterate over elements in the current color array.
|
||||
backgrounds[ i ].forEach( ( selector ) => {
|
||||
// Find the element using the selector.
|
||||
const $background = el.$wrapper.find( selector );
|
||||
|
||||
// Set the color value for the element.
|
||||
$background.val( color );
|
||||
|
||||
// Update the background color in the color picker swatch.
|
||||
$background.next().find( '.minicolors-swatch-color' ).css( 'backgroundColor', color );
|
||||
} );
|
||||
|
||||
// Update the background color for the image element.
|
||||
$img.find( 'img' ).css( 'backgroundColor', color );
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery, wpforms_admin_email_settings ) );
|
||||
|
||||
// Initialize.
|
||||
WPFormsEmailSettings.init();
|
||||
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,596 @@
|
||||
/* global wpforms_admin_form_embed_wizard, WPFormsBuilder, ajaxurl, WPFormsChallenge, wpforms_builder, WPForms */
|
||||
|
||||
/**
|
||||
* Form Embed Wizard function.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var WPFormsFormEmbedWizard = window.WPFormsFormEmbedWizard || ( function( document, window, $ ) {
|
||||
|
||||
/**
|
||||
* Elements.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var el = {};
|
||||
|
||||
/**
|
||||
* Runtime variables.
|
||||
*
|
||||
* @since 1.6.2
|
||||
* @since 1.7.9 Added `lastEmbedSearchPageTerm` property.
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var vars = {
|
||||
formId: 0,
|
||||
isBuilder: false,
|
||||
isChallengeActive: false,
|
||||
lastEmbedSearchPageTerm: '',
|
||||
};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
init: function() {
|
||||
|
||||
$( app.ready );
|
||||
$( window ).on( 'load', function() {
|
||||
|
||||
// in case of jQuery 3.+ we need to wait for an `ready` event first.
|
||||
if ( typeof $.ready.then === 'function' ) {
|
||||
$.ready.then( app.load );
|
||||
} else {
|
||||
app.load();
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
ready: function() {
|
||||
|
||||
app.initVars();
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Window load.
|
||||
*
|
||||
* @since 1.6.2
|
||||
* @since 1.7.9 Initialize 'Select Pages' ChoicesJS.
|
||||
*/
|
||||
load: function() {
|
||||
|
||||
// Initialize tooltip in page editor.
|
||||
if ( wpforms_admin_form_embed_wizard.is_edit_page === '1' && ! vars.isChallengeActive ) {
|
||||
app.initTooltip();
|
||||
}
|
||||
|
||||
// Initialize wizard state in the form builder only.
|
||||
if ( vars.isBuilder ) {
|
||||
app.initialStateToggle();
|
||||
}
|
||||
|
||||
app.initSelectPagesChoicesJS();
|
||||
|
||||
$( document ).on( 'wpformsWizardPopupClose', app.enableLetsGoButton );
|
||||
},
|
||||
|
||||
/**
|
||||
* Init variables.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
initVars: function() {
|
||||
|
||||
// Caching some DOM elements for further use.
|
||||
el = {
|
||||
$wizardContainer: $( '#wpforms-admin-form-embed-wizard-container' ),
|
||||
$wizard: $( '#wpforms-admin-form-embed-wizard' ),
|
||||
$contentInitial: $( '#wpforms-admin-form-embed-wizard-content-initial' ),
|
||||
$contentSelectPage: $( '#wpforms-admin-form-embed-wizard-content-select-page' ),
|
||||
$contentCreatePage: $( '#wpforms-admin-form-embed-wizard-content-create-page' ),
|
||||
$sectionBtns: $( '#wpforms-admin-form-embed-wizard-section-btns' ),
|
||||
$sectionGo: $( '#wpforms-admin-form-embed-wizard-section-go' ),
|
||||
$newPageTitle: $( '#wpforms-admin-form-embed-wizard-new-page-title' ),
|
||||
$selectPage: $( '#wpforms-setting-form-embed-wizard-choicesjs-select-pages' ),
|
||||
$videoTutorial: $( '#wpforms-admin-form-embed-wizard-tutorial' ),
|
||||
$sectionToggles: $( '#wpforms-admin-form-embed-wizard-section-toggles' ),
|
||||
$sectionGoBack: $( '#wpforms-admin-form-embed-wizard-section-goback' ),
|
||||
$shortcode: $( '#wpforms-admin-form-embed-wizard-shortcode-wrap' ),
|
||||
$shortcodeInput: $( '#wpforms-admin-form-embed-wizard-shortcode' ),
|
||||
$shortcodeCopy: $( '#wpforms-admin-form-embed-wizard-shortcode-copy' ),
|
||||
};
|
||||
|
||||
el.$selectPageContainer = el.$selectPage.parents( 'span.choicesjs-select-wrap' );
|
||||
|
||||
// Detect the form builder screen and store the flag.
|
||||
vars.isBuilder = typeof WPFormsBuilder !== 'undefined';
|
||||
|
||||
// Detect the Challenge and store the flag.
|
||||
vars.isChallengeActive = typeof WPFormsChallenge !== 'undefined';
|
||||
|
||||
// Are the pages exists?
|
||||
vars.pagesExists = el.$wizard.data( 'pages-exists' ) === 1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Init ChoicesJS for "Select Pages" field in embed.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*/
|
||||
initSelectPagesChoicesJS: function() {
|
||||
|
||||
if ( el.$selectPage.length <= 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const useAjax = el.$selectPage.data( 'use_ajax' ) === 1;
|
||||
|
||||
WPForms.Admin.Builder.WPFormsChoicesJS.setup(
|
||||
el.$selectPage[0],
|
||||
{},
|
||||
{
|
||||
action: 'wpforms_admin_form_embed_wizard_search_pages_choicesjs',
|
||||
nonce: useAjax ? wpforms_admin_form_embed_wizard.nonce : null,
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Register JS events.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
events: function() {
|
||||
|
||||
// Skip wizard events in the page editor.
|
||||
if ( ! el.$wizard.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
el.$wizard
|
||||
.on( 'click', 'button', app.popupButtonsClick )
|
||||
.on( 'click', '.tutorial-toggle', app.tutorialToggle )
|
||||
.on( 'click', '.shortcode-toggle', app.shortcodeToggle )
|
||||
.on( 'click', '.initialstate-toggle', app.initialStateToggle )
|
||||
.on( 'click', '.wpforms-admin-popup-close', app.closePopup )
|
||||
.on( 'click', '#wpforms-admin-form-embed-wizard-shortcode-copy', app.copyShortcodeToClipboard )
|
||||
.on( 'keyup', '#wpforms-admin-form-embed-wizard-new-page-title', app.enableLetsGoButton );
|
||||
},
|
||||
|
||||
/**
|
||||
* Popup buttons events handler.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*
|
||||
* @param {object} e Event object.
|
||||
*/
|
||||
popupButtonsClick: function( e ) {
|
||||
|
||||
var $btn = $( e.target );
|
||||
|
||||
if ( ! $btn.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var $div = $btn.closest( 'div' ),
|
||||
action = $btn.data( 'action' ) || '';
|
||||
|
||||
el.$contentInitial.hide();
|
||||
|
||||
switch ( action ) {
|
||||
|
||||
// Select existing page.
|
||||
case 'select-page':
|
||||
el.$newPageTitle.hide();
|
||||
el.$contentSelectPage.show();
|
||||
break;
|
||||
|
||||
// Create a new page.
|
||||
case 'create-page':
|
||||
el.$selectPageContainer.hide();
|
||||
el.$contentCreatePage.show();
|
||||
break;
|
||||
|
||||
// Let's Go!
|
||||
case 'go':
|
||||
if ( el.$selectPageContainer.is( ':visible' ) && el.$selectPage.val() === '' ) {
|
||||
return;
|
||||
}
|
||||
$btn.prop( 'disabled', true );
|
||||
app.saveFormAndRedirect();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$div.hide();
|
||||
$div.next().fadeIn();
|
||||
el.$sectionToggles.hide();
|
||||
el.$sectionGoBack.fadeIn();
|
||||
|
||||
// Set focus to the field that is currently displayed.
|
||||
$.each( [ el.$selectPage, el.$newPageTitle ], function() {
|
||||
if ( this.is( ':visible' ) ) {
|
||||
this.trigger( 'focus' );
|
||||
}
|
||||
} );
|
||||
|
||||
app.tutorialControl( 'Stop' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle video tutorial inside popup.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*
|
||||
* @param {object} e Event object.
|
||||
*/
|
||||
tutorialToggle: function( e ) {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
el.$shortcode.hide();
|
||||
el.$videoTutorial.toggle();
|
||||
|
||||
if ( el.$videoTutorial.attr( 'src' ) === 'about:blank' ) {
|
||||
el.$videoTutorial.attr( 'src', wpforms_admin_form_embed_wizard.video_url );
|
||||
}
|
||||
|
||||
if ( el.$videoTutorial[0].src.indexOf( '&autoplay=1' ) < 0 ) {
|
||||
app.tutorialControl( 'Play' );
|
||||
} else {
|
||||
app.tutorialControl( 'Stop' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle video tutorial inside popup.
|
||||
*
|
||||
* @since 1.6.2.3
|
||||
*
|
||||
* @param {string} action One of 'Play' or 'Stop'.
|
||||
*/
|
||||
tutorialControl: function( action ) {
|
||||
|
||||
var iframe = el.$videoTutorial[0];
|
||||
|
||||
if ( typeof iframe === 'undefined' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( action !== 'Stop' ) {
|
||||
iframe.src += iframe.src.indexOf( '&autoplay=1' ) < 0 ? '&autoplay=1' : '';
|
||||
} else {
|
||||
iframe.src = iframe.src.replace( '&autoplay=1', '' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle shortcode input field.
|
||||
*
|
||||
* @since 1.6.2.3
|
||||
*
|
||||
* @param {object} e Event object.
|
||||
*/
|
||||
shortcodeToggle: function( e ) {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
el.$videoTutorial.hide();
|
||||
app.tutorialControl( 'Stop' );
|
||||
el.$shortcodeInput.val( '[wpforms id="' + vars.formId + '" title="false"]' );
|
||||
el.$shortcode.toggle();
|
||||
},
|
||||
|
||||
/**
|
||||
* Enable the "Let's Go!" button.
|
||||
*
|
||||
* @since 1.8.2.3
|
||||
*/
|
||||
enableLetsGoButton: function() {
|
||||
|
||||
const $btn = el.$sectionGo.find( 'button' );
|
||||
|
||||
$btn.prop( 'disabled', false );
|
||||
},
|
||||
|
||||
/**
|
||||
* Copies the shortcode embed code to the clipboard.
|
||||
*
|
||||
* @since 1.6.4
|
||||
*/
|
||||
copyShortcodeToClipboard: function() {
|
||||
|
||||
// Remove disabled attribute, select the text, and re-add disabled attribute.
|
||||
el.$shortcodeInput
|
||||
.prop( 'disabled', false )
|
||||
.select()
|
||||
.prop( 'disabled', true );
|
||||
|
||||
// Copy it.
|
||||
document.execCommand( 'copy' );
|
||||
|
||||
var $icon = el.$shortcodeCopy.find( 'i' );
|
||||
|
||||
// Add visual feedback to copy command.
|
||||
$icon.removeClass( 'fa-files-o' ).addClass( 'fa-check' );
|
||||
|
||||
// Reset visual confirmation back to default state after 2.5 sec.
|
||||
window.setTimeout( function() {
|
||||
$icon.removeClass( 'fa-check' ).addClass( 'fa-files-o' );
|
||||
}, 2500 );
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle initial state.
|
||||
*
|
||||
* @since 1.6.2.3
|
||||
*
|
||||
* @param {object} e Event object.
|
||||
*/
|
||||
initialStateToggle: function( e ) {
|
||||
|
||||
if ( e ) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
if ( vars.pagesExists ) {
|
||||
el.$contentInitial.show();
|
||||
el.$contentSelectPage.hide();
|
||||
el.$contentCreatePage.hide();
|
||||
el.$selectPageContainer.show();
|
||||
el.$newPageTitle.show();
|
||||
el.$sectionBtns.show();
|
||||
el.$sectionGo.hide();
|
||||
} else {
|
||||
el.$contentInitial.hide();
|
||||
el.$contentSelectPage.hide();
|
||||
el.$contentCreatePage.show();
|
||||
el.$selectPageContainer.hide();
|
||||
el.$newPageTitle.show();
|
||||
el.$sectionBtns.hide();
|
||||
el.$sectionGo.show();
|
||||
}
|
||||
el.$shortcode.hide();
|
||||
el.$videoTutorial.hide();
|
||||
app.tutorialControl( 'Stop' );
|
||||
el.$sectionToggles.show();
|
||||
el.$sectionGoBack.hide();
|
||||
},
|
||||
|
||||
/**
|
||||
* Save the form and redirect to form embed page.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
saveFormAndRedirect: function() {
|
||||
|
||||
// Just redirect if no need to save the form.
|
||||
if ( ! vars.isBuilder || WPFormsBuilder.formIsSaved() ) {
|
||||
app.embedPageRedirect();
|
||||
return;
|
||||
}
|
||||
|
||||
// Embedding in Challenge should save the form silently.
|
||||
if ( vars.isBuilder && vars.isChallengeActive ) {
|
||||
WPFormsBuilder.formSave().done( app.embedPageRedirect );
|
||||
return;
|
||||
}
|
||||
|
||||
$.confirm( {
|
||||
title: false,
|
||||
content: wpforms_builder.exit_confirm,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
closeIcon: true,
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_builder.save_embed,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action: function() {
|
||||
WPFormsBuilder.formSave().done( app.embedPageRedirect );
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_builder.embed,
|
||||
action: function() {
|
||||
WPFormsBuilder.setCloseConfirmation( false );
|
||||
app.embedPageRedirect();
|
||||
},
|
||||
},
|
||||
},
|
||||
onClose: function() {
|
||||
el.$sectionGo.find( 'button' ).prop( 'disabled', false );
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepare data for requesting redirect URL.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*
|
||||
* @returns {object} AJAX data object.
|
||||
*/
|
||||
embedPageRedirectAjaxData: function() {
|
||||
|
||||
var data = {
|
||||
action : 'wpforms_admin_form_embed_wizard_embed_page_url',
|
||||
_wpnonce: wpforms_admin_form_embed_wizard.nonce,
|
||||
formId: vars.formId,
|
||||
};
|
||||
|
||||
if ( el.$selectPageContainer.is( ':visible' ) ) {
|
||||
data.pageId = el.$selectPage.val();
|
||||
}
|
||||
|
||||
if ( el.$newPageTitle.is( ':visible' ) ) {
|
||||
data.pageTitle = el.$newPageTitle.val();
|
||||
}
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Redirect to form embed page.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
embedPageRedirect: function() {
|
||||
|
||||
var data = app.embedPageRedirectAjaxData();
|
||||
|
||||
// Exit if no one page is selected.
|
||||
if ( typeof data.pageId !== 'undefined' && data.pageId === '' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.post( ajaxurl, data, function( response ) {
|
||||
if ( response.success ) {
|
||||
window.location = response.data;
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Display wizard popup.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*
|
||||
* @param {numeric} openFormId Form ID to embed. Used only if called outside the form builder.
|
||||
*/
|
||||
openPopup: function( openFormId ) {
|
||||
|
||||
openFormId = openFormId || 0;
|
||||
|
||||
vars.formId = vars.isBuilder ? $( '#wpforms-builder-form' ).data( 'id' ) : openFormId;
|
||||
|
||||
// Regular wizard and wizard in Challenge has differences.
|
||||
el.$wizard.toggleClass( 'wpforms-challenge-popup', vars.isChallengeActive );
|
||||
el.$wizard.find( '.wpforms-admin-popup-content-regular' ).toggle( ! vars.isChallengeActive );
|
||||
el.$wizard.find( '.wpforms-admin-popup-content-challenge' ).toggle( vars.isChallengeActive );
|
||||
|
||||
// Re-init sections.
|
||||
if ( el.$selectPage.length === 0 ) {
|
||||
el.$sectionBtns.hide();
|
||||
el.$sectionGo.show();
|
||||
} else {
|
||||
el.$sectionBtns.show();
|
||||
el.$sectionGo.hide();
|
||||
}
|
||||
el.$newPageTitle.show();
|
||||
el.$selectPageContainer.show();
|
||||
|
||||
el.$wizardContainer.fadeIn();
|
||||
},
|
||||
|
||||
/**
|
||||
* Close wizard popup.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
closePopup: function() {
|
||||
|
||||
el.$wizardContainer.fadeOut();
|
||||
app.initialStateToggle();
|
||||
|
||||
$( document ).trigger( 'wpformsWizardPopupClose' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Init embed page tooltip.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*/
|
||||
initTooltip: function() {
|
||||
|
||||
if ( typeof $.fn.tooltipster === 'undefined' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var $dot = $( '<span class="wpforms-admin-form-embed-wizard-dot"> </span>' ),
|
||||
isGutenberg = app.isGutenberg(),
|
||||
anchor = isGutenberg ? '.block-editor .edit-post-header' : '#wp-content-editor-tools .wpforms-insert-form-button';
|
||||
|
||||
var tooltipsterArgs = {
|
||||
content : $( '#wpforms-admin-form-embed-wizard-tooltip-content' ),
|
||||
trigger : 'custom',
|
||||
interactive : true,
|
||||
animationDuration: 0,
|
||||
delay : 0,
|
||||
theme : [ 'tooltipster-default', 'wpforms-admin-form-embed-wizard' ],
|
||||
side : isGutenberg ? 'bottom' : 'right',
|
||||
distance : 3,
|
||||
functionReady : function( instance, helper ) {
|
||||
|
||||
instance._$tooltip.on( 'click', 'button', function() {
|
||||
|
||||
instance.close();
|
||||
$( '.wpforms-admin-form-embed-wizard-dot' ).remove();
|
||||
} );
|
||||
|
||||
instance.reposition();
|
||||
},
|
||||
};
|
||||
|
||||
if ( ! isGutenberg ) {
|
||||
$dot.insertAfter( anchor ).tooltipster( tooltipsterArgs ).tooltipster( 'open' );
|
||||
}
|
||||
|
||||
// The Gutenberg header can be loaded after the window load event.
|
||||
// We have to wait until the Gutenberg heading is added to the DOM.
|
||||
const closeAnchorListener = wp.data.subscribe( function() {
|
||||
|
||||
if ( ! $( anchor ).length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Close the listener to avoid an infinite loop.
|
||||
closeAnchorListener();
|
||||
|
||||
$dot.insertAfter( anchor ).tooltipster( tooltipsterArgs ).tooltipster( 'open' );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if we're in Gutenberg editor.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*
|
||||
* @returns {boolean} Is Gutenberg or not.
|
||||
*/
|
||||
isGutenberg: function() {
|
||||
|
||||
return typeof wp !== 'undefined' && Object.prototype.hasOwnProperty.call( wp, 'blocks' );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPFormsFormEmbedWizard.init();
|
||||
+1
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
+10
File diff suppressed because one or more lines are too long
@@ -0,0 +1,134 @@
|
||||
/* global wpforms_admin */
|
||||
|
||||
/**
|
||||
* Logger scripts
|
||||
*
|
||||
* @since 1.6.3
|
||||
*/
|
||||
|
||||
const WPFormsLogger = window.WPFormsLogger || ( function( document, window, $ ) {
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
ready() {
|
||||
app.bindEvents();
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind popup to the click on logger link.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*/
|
||||
bindPopup() {
|
||||
$( '.wpforms-list-table--logs .wp-list-table' ).on( 'click', '.js-single-log-target', function( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
app.showPopup( $( this ).attr( 'data-log-id' ) );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events.
|
||||
*
|
||||
* @since 1.8.9
|
||||
*/
|
||||
bindEvents() {
|
||||
app.bindPopup();
|
||||
|
||||
$( '#wpforms-setting-logs-enable' ).change( function() {
|
||||
app.toggleLogs( $( this ).is( ':checked' ) );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle logs settings and logs list.
|
||||
*
|
||||
* @since 1.8.9
|
||||
*
|
||||
* @param {boolean} checked Checked state.
|
||||
*/
|
||||
toggleLogs( checked ) {
|
||||
// Toggle hidden class.
|
||||
$( '.wpforms-logs-settings' ).toggleClass( 'wpforms-hidden', ! checked );
|
||||
},
|
||||
|
||||
/**
|
||||
* Show popup.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @param {number} recordId Record Id.
|
||||
*/
|
||||
showPopup( recordId ) {
|
||||
if ( ! recordId ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const popupTemplate = wp.template( 'wpforms-log-record' );
|
||||
|
||||
$.dialog( {
|
||||
title: false,
|
||||
boxWidth: Math.min( 1200, $( window ).width() * 0.8 ),
|
||||
content() {
|
||||
const self = this;
|
||||
|
||||
return $.get(
|
||||
wpforms_admin.ajax_url,
|
||||
{
|
||||
action: 'wpforms_get_log_record',
|
||||
nonce: wpforms_admin.nonce,
|
||||
recordId,
|
||||
}
|
||||
).done( function( res ) {
|
||||
if ( ! res.success || ! res.data ) {
|
||||
app.error( res.data );
|
||||
self.close();
|
||||
|
||||
return;
|
||||
}
|
||||
self.setContent( popupTemplate( res.data ) );
|
||||
} ).fail( function( xhr, textStatus ) {
|
||||
app.error( textStatus + ' ' + xhr.responseText );
|
||||
self.close();
|
||||
} );
|
||||
},
|
||||
animation: 'scale',
|
||||
columnClass: 'medium',
|
||||
closeIcon: true,
|
||||
closeAnimation: 'scale',
|
||||
backgroundDismiss: true,
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Output error to the console if debug mode is on.
|
||||
*
|
||||
* @since 1.6.4
|
||||
*
|
||||
* @param {string} msg Error text.
|
||||
*/
|
||||
error( msg ) {
|
||||
if ( ! wpforms_admin.debug ) {
|
||||
return;
|
||||
}
|
||||
|
||||
msg = msg ? ': ' + msg : '';
|
||||
// eslint-disable-next-line no-console
|
||||
console.log( 'WPForms Debug: Error receiving log record data' + msg );
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPFormsLogger.init();
|
||||
+1
@@ -0,0 +1 @@
|
||||
let WPFormsLogger=window.WPFormsLogger||((t,n)=>{let s={init(){n(s.ready)},ready(){s.bindEvents()},bindPopup(){n(".wpforms-list-table--logs .wp-list-table").on("click",".js-single-log-target",function(o){o.preventDefault(),s.showPopup(n(this).attr("data-log-id"))})},bindEvents(){s.bindPopup(),n("#wpforms-setting-logs-enable").change(function(){s.toggleLogs(n(this).is(":checked"))})},toggleLogs(o){n(".wpforms-logs-settings").toggleClass("wpforms-hidden",!o)},showPopup(o){if(o){let e=wp.template("wpforms-log-record");n.dialog({title:!1,boxWidth:Math.min(1200,.8*n(t).width()),content(){let t=this;return n.get(wpforms_admin.ajax_url,{action:"wpforms_get_log_record",nonce:wpforms_admin.nonce,recordId:o}).done(function(o){o.success&&o.data?t.setContent(e(o.data)):(s.error(o.data),t.close())}).fail(function(o,e){s.error(e+" "+o.responseText),t.close()})},animation:"scale",columnClass:"medium",closeIcon:!0,closeAnimation:"scale",backgroundDismiss:!0})}},error(o){wpforms_admin.debug&&(o=o?": "+o:"",console.log("WPForms Debug: Error receiving log record data"+o))}};return s})((document,window),jQuery);WPFormsLogger.init();
|
||||
@@ -0,0 +1,81 @@
|
||||
/* global wpforms_admin_notices */
|
||||
|
||||
/**
|
||||
* WPForms Dismissible Notices.
|
||||
*
|
||||
* @since 1.6.7.1
|
||||
*/
|
||||
|
||||
var WPFormsAdminNotices = window.WPFormsAdminNotices || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.6.7.1
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.6.7.1
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.6.7.1
|
||||
*/
|
||||
ready() {
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Dismissible notices events.
|
||||
*
|
||||
* @since 1.6.7.1
|
||||
*/
|
||||
events() {
|
||||
$( document ).on(
|
||||
'click',
|
||||
'.wpforms-notice .notice-dismiss, .wpforms-notice .wpforms-notice-dismiss',
|
||||
app.dismissNotice
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Dismiss notice event handler.
|
||||
*
|
||||
* @since 1.6.7.1
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
*/
|
||||
dismissNotice( e ) {
|
||||
const $element = $( e.target );
|
||||
|
||||
if ( ! $element.hasClass( 'wpforms-review-out' ) ) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
$element.closest( '.wpforms-notice' ).remove();
|
||||
|
||||
$.post(
|
||||
wpforms_admin_notices.ajax_url,
|
||||
{
|
||||
action: 'wpforms_notice_dismiss',
|
||||
nonce: wpforms_admin_notices.nonce,
|
||||
id: ( $element.closest( '.wpforms-notice' ).attr( 'id' ) || '' ).replace( 'wpforms-notice-', '' ),
|
||||
}
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPFormsAdminNotices.init();
|
||||
+1
@@ -0,0 +1 @@
|
||||
var WPFormsAdminNotices=window.WPFormsAdminNotices||((s,o)=>{var i={init(){o(i.ready)},ready(){i.events()},events(){o(s).on("click",".wpforms-notice .notice-dismiss, .wpforms-notice .wpforms-notice-dismiss",i.dismissNotice)},dismissNotice(s){var i=o(s.target);i.hasClass("wpforms-review-out")||s.preventDefault(),i.closest(".wpforms-notice").remove(),o.post(wpforms_admin_notices.ajax_url,{action:"wpforms_notice_dismiss",nonce:wpforms_admin_notices.nonce,id:(i.closest(".wpforms-notice").attr("id")||"").replace("wpforms-notice-","")})}};return i})(document,(window,jQuery));WPFormsAdminNotices.init();
|
||||
@@ -0,0 +1,276 @@
|
||||
/* global wpforms_pluginlanding, wpforms_admin */
|
||||
|
||||
/**
|
||||
* @param wpforms_pluginlanding.activated
|
||||
* @param wpforms_pluginlanding.activated_pro
|
||||
* @param wpforms_pluginlanding.download_now
|
||||
* @param wpforms_pluginlanding.error_could_not_activate
|
||||
* @param wpforms_pluginlanding.error_could_not_install
|
||||
* @param wpforms_pluginlanding.is_activated
|
||||
* @param wpforms_pluginlanding.license_level
|
||||
* @param wpforms_pluginlanding.result_status
|
||||
* @param wpforms_pluginlanding.plugins_page
|
||||
* @param wpforms_pluginlanding.setup_status
|
||||
* @param wpforms_pluginlanding.step3_button_url
|
||||
* @param wpforms_pluginlanding.manual_activate_url
|
||||
* @param wpforms_pluginlanding.manual_install_url
|
||||
*/
|
||||
|
||||
/**
|
||||
* Landing Pages Common.
|
||||
*
|
||||
* @since 1.9.8.6
|
||||
*/
|
||||
const WPFormsPagesCommon = window.WPFormsPagesCommon || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Elements.
|
||||
*
|
||||
* @since 1.9.8.6
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
let el = {};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.9.8.6
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.9.8.6
|
||||
*/
|
||||
init: () => {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.9.8.6
|
||||
*/
|
||||
ready: () => {
|
||||
app.initVars();
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Init variables.
|
||||
*
|
||||
* @since 1.9.8.6
|
||||
*/
|
||||
initVars: () => {
|
||||
el = {
|
||||
$stepInstall: $( 'section.step-install' ),
|
||||
$stepInstallNum: $( 'section.step-install .num img' ),
|
||||
$stepSetup: $( 'section.step-setup' ),
|
||||
$stepSetupNum: $( 'section.step-setup .num img' ),
|
||||
$stepResult: $( 'section.step-result' ),
|
||||
$stepResultNum: $( 'section.step-result .num img' ),
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Register JS events.
|
||||
*
|
||||
* @since 1.9.8.6
|
||||
*/
|
||||
events: () => {
|
||||
// Step the 'Install' button click.
|
||||
el.$stepInstall.on( 'click', 'button', app.stepInstallClick );
|
||||
|
||||
// Step 'Setup' button click.
|
||||
el.$stepSetup.on( 'click', 'button', app.gotoURL );
|
||||
|
||||
// Step the 'Addon' button click.
|
||||
el.$stepResult.on( 'click', 'button', app.gotoURL );
|
||||
},
|
||||
|
||||
/**
|
||||
* Step the 'Install' button click.
|
||||
*
|
||||
* @since 1.9.8.6
|
||||
*
|
||||
* @param {Event} e Event object.
|
||||
*/
|
||||
stepInstallClick: ( e ) => {
|
||||
const $btn = $( e.currentTarget );
|
||||
|
||||
if ( $btn.hasClass( 'disabled' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const action = $btn.attr( 'data-action' );
|
||||
|
||||
let ajaxAction = '';
|
||||
|
||||
switch ( action ) {
|
||||
case 'activate':
|
||||
ajaxAction = 'wpforms_activate_addon';
|
||||
$btn.text( wpforms_pluginlanding.activating );
|
||||
break;
|
||||
|
||||
case 'install':
|
||||
ajaxAction = 'wpforms_install_addon';
|
||||
$btn.text( wpforms_pluginlanding.installing );
|
||||
break;
|
||||
|
||||
case 'goto-url':
|
||||
window.location.href = $btn.attr( 'data-url' );
|
||||
return;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
$btn.addClass( 'disabled' );
|
||||
app.showSpinner( el.$stepInstallNum );
|
||||
|
||||
const plugin = $btn.attr( 'data-plugin' );
|
||||
|
||||
const data = {
|
||||
action: ajaxAction,
|
||||
nonce : wpforms_admin.nonce,
|
||||
plugin,
|
||||
type : 'plugin',
|
||||
};
|
||||
$.post( wpforms_admin.ajax_url, data )
|
||||
.done( function( res ) {
|
||||
app.stepInstallDone( res, $btn, action );
|
||||
} )
|
||||
.always( function() {
|
||||
app.hideSpinner( el.$stepInstallNum );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Done part of the step 'Install'.
|
||||
*
|
||||
* @since 1.9.8.6
|
||||
*
|
||||
* @param {Object} res Result of $.post() query.
|
||||
* @param {jQuery} $btn Button.
|
||||
* @param {string} action Action (for more info look at the app.stepInstallClick() function).
|
||||
*/
|
||||
stepInstallDone: ( res, $btn, action ) => { // eslint-disable-line complexity
|
||||
const success = 'install' === action ? res.success && res.data.is_activated : res.success,
|
||||
provider = $btn.data( 'provider' );
|
||||
|
||||
if ( success ) {
|
||||
el.$stepInstallNum.attr( 'src', el.$stepInstallNum.attr( 'src' ).replace( 'step-1.', 'step-complete.' ) );
|
||||
$btn.addClass( 'grey' ).removeClass( 'button-primary' ).text( wpforms_pluginlanding.activated );
|
||||
app.stepInstallPluginStatus( provider );
|
||||
} else {
|
||||
const activationFail = ( 'install' === action && res.success && ! res.data.is_activated ) || 'activate' === action,
|
||||
installUrl = wpforms_pluginlanding[ provider + '_manual_install_url' ] || '',
|
||||
activateUrl = wpforms_pluginlanding[ provider + '_manual_activate_url' ] || '',
|
||||
url = ! activationFail ? installUrl : activateUrl,
|
||||
msg = ! activationFail ? wpforms_pluginlanding.error_could_not_install : wpforms_pluginlanding.error_could_not_activate,
|
||||
btn = ! activationFail ? wpforms_pluginlanding.download_now : wpforms_pluginlanding.plugins_page;
|
||||
|
||||
$btn.removeClass( 'grey disabled' ).text( btn ).attr( 'data-action', 'goto-url' ).attr( 'data-url', url );
|
||||
$btn.after( '<p class="error">' + msg + '</p>' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for step 'Install' completion.
|
||||
*
|
||||
* @since 1.9.8.6
|
||||
*
|
||||
* @param {string} plugin Plugin name.
|
||||
*/
|
||||
stepInstallPluginStatus: ( plugin ) => {
|
||||
const data = {
|
||||
action: 'wpforms_page_check_' + plugin + '_status',
|
||||
nonce: wpforms_admin.nonce,
|
||||
provider: plugin,
|
||||
};
|
||||
$.post( wpforms_admin.ajax_url, data ).done( app.stepInstallPluginStatusDone );
|
||||
},
|
||||
|
||||
/**
|
||||
* Done part of the callback for step 'Install' completion.
|
||||
*
|
||||
* @since 1.9.8.6
|
||||
*
|
||||
* @param {Object} res Result of $.post() query.
|
||||
*/
|
||||
stepInstallPluginStatusDone: ( res ) => {
|
||||
if ( ! res.success ) {
|
||||
return;
|
||||
}
|
||||
|
||||
el.$stepSetup.removeClass( 'grey' );
|
||||
el.$stepSetupBtn = el.$stepSetup.find( 'button' );
|
||||
|
||||
if ( res.data.setup_status > 0 ) {
|
||||
el.$stepSetupNum.attr( 'src', el.$stepSetupNum.attr( 'src' ).replace( 'step-2.svg', 'step-complete.svg' ) );
|
||||
el.$stepResult.removeClass( 'grey' );
|
||||
el.$stepResultBtn = el.$stepResult.find( 'button' );
|
||||
|
||||
if ( res.data.license_level === 'pro' && res.data.result_status === true ) {
|
||||
el.$stepResultBtn.text( wpforms_pluginlanding.activated_pro );
|
||||
el.$stepResultNum.attr( 'src', el.$stepResultNum.attr( 'src' ).replace( 'step-3.svg', 'step-complete.svg' ) );
|
||||
} else {
|
||||
el.$stepResultBtn.attr( 'data-url', res.data.step3_button_url );
|
||||
el.$stepResultBtn.removeClass( 'grey disabled' ).addClass( 'button-primary' );
|
||||
}
|
||||
} else {
|
||||
el.$stepSetupBtn.removeClass( 'grey disabled' ).addClass( 'button-primary' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Go to URL.
|
||||
*
|
||||
* @since 1.9.8.6
|
||||
*
|
||||
* @param {Event} e Event object.
|
||||
*/
|
||||
gotoURL: ( e ) => { // eslint-disable-line no-unused-vars
|
||||
const $btn = $( e.currentTarget ),
|
||||
url = $btn.attr( 'data-url' );
|
||||
|
||||
if ( $btn.hasClass( 'disabled' ) || ! url ) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.open( url, '_blank' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Show spinner.
|
||||
*
|
||||
* @since 1.9.8.6
|
||||
*
|
||||
* @param {jQuery} $el Element.
|
||||
*/
|
||||
showSpinner: ( $el ) => {
|
||||
$el.siblings( 'i.loader' ).removeClass( 'hidden' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide spinner.
|
||||
*
|
||||
* @since 1.9.8.6
|
||||
*
|
||||
* @param {jQuery} $el Element.
|
||||
*/
|
||||
hideSpinner: ( $el ) => {
|
||||
$el.show();
|
||||
$el.siblings( 'i.loader' ).addClass( 'hidden' );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide public access to functions and properties.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPFormsPagesCommon.init();
|
||||
+1
@@ -0,0 +1 @@
|
||||
let WPFormsPagesCommon=window.WPFormsPagesCommon||((n,l)=>{let r={},i={init:()=>{l(i.ready)},ready:()=>{i.initVars(),i.events()},initVars:()=>{r={$stepInstall:l("section.step-install"),$stepInstallNum:l("section.step-install .num img"),$stepSetup:l("section.step-setup"),$stepSetupNum:l("section.step-setup .num img"),$stepResult:l("section.step-result"),$stepResultNum:l("section.step-result .num img")}},events:()=>{r.$stepInstall.on("click","button",i.stepInstallClick),r.$stepSetup.on("click","button",i.gotoURL),r.$stepResult.on("click","button",i.gotoURL)},stepInstallClick:e=>{let a=l(e.currentTarget);if(!a.hasClass("disabled")){let s=a.attr("data-action"),t="";switch(s){case"activate":t="wpforms_activate_addon",a.text(wpforms_pluginlanding.activating);break;case"install":t="wpforms_install_addon",a.text(wpforms_pluginlanding.installing);break;case"goto-url":return void(n.location.href=a.attr("data-url"));default:return}a.addClass("disabled"),i.showSpinner(r.$stepInstallNum);e=a.attr("data-plugin"),e={action:t,nonce:wpforms_admin.nonce,plugin:e,type:"plugin"};l.post(wpforms_admin.ajax_url,e).done(function(t){i.stepInstallDone(t,a,s)}).always(function(){i.hideSpinner(r.$stepInstallNum)})}},stepInstallDone:(t,s,e)=>{var a="install"===e?t.success&&t.data.is_activated:t.success,n=s.data("provider");a?(r.$stepInstallNum.attr("src",r.$stepInstallNum.attr("src").replace("step-1.","step-complete.")),s.addClass("grey").removeClass("button-primary").text(wpforms_pluginlanding.activated),i.stepInstallPluginStatus(n)):(a="install"===e&&t.success&&!t.data.is_activated||"activate"===e,t=wpforms_pluginlanding[n+"_manual_install_url"]||"",e=a?wpforms_pluginlanding[n+"_manual_activate_url"]||"":t,n=a?wpforms_pluginlanding.error_could_not_activate:wpforms_pluginlanding.error_could_not_install,t=a?wpforms_pluginlanding.plugins_page:wpforms_pluginlanding.download_now,s.removeClass("grey disabled").text(t).attr("data-action","goto-url").attr("data-url",e),s.after('<p class="error">'+n+"</p>"))},stepInstallPluginStatus:t=>{t={action:"wpforms_page_check_"+t+"_status",nonce:wpforms_admin.nonce,provider:t};l.post(wpforms_admin.ajax_url,t).done(i.stepInstallPluginStatusDone)},stepInstallPluginStatusDone:t=>{t.success&&(r.$stepSetup.removeClass("grey"),r.$stepSetupBtn=r.$stepSetup.find("button"),0<t.data.setup_status?(r.$stepSetupNum.attr("src",r.$stepSetupNum.attr("src").replace("step-2.svg","step-complete.svg")),r.$stepResult.removeClass("grey"),r.$stepResultBtn=r.$stepResult.find("button"),"pro"===t.data.license_level&&!0===t.data.result_status?(r.$stepResultBtn.text(wpforms_pluginlanding.activated_pro),r.$stepResultNum.attr("src",r.$stepResultNum.attr("src").replace("step-3.svg","step-complete.svg"))):(r.$stepResultBtn.attr("data-url",t.data.step3_button_url),r.$stepResultBtn.removeClass("grey disabled").addClass("button-primary"))):r.$stepSetupBtn.removeClass("grey disabled").addClass("button-primary"))},gotoURL:t=>{var t=l(t.currentTarget),s=t.attr("data-url");!t.hasClass("disabled")&&s&&n.open(s,"_blank")},showSpinner:t=>{t.siblings("i.loader").removeClass("hidden")},hideSpinner:t=>{t.show(),t.siblings("i.loader").addClass("hidden")}};return i})((document,window),jQuery);WPFormsPagesCommon.init();
|
||||
@@ -0,0 +1,247 @@
|
||||
/* global wpforms_admin, WPFormsFormTemplates, wpforms_admin_form_templates, wpf */
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
|
||||
/**
|
||||
* @param wpforms_admin_form_templates.openAIFormUrl
|
||||
*/
|
||||
/**
|
||||
* Admin Subpage Form Templates function.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
var WPFormsAdminFormTemplates = window.WPFormsAdminFormTemplates || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
ready() {
|
||||
WPFormsFormTemplates.setup();
|
||||
app.events();
|
||||
wpf.initTooltips();
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*/
|
||||
events() {
|
||||
$( '.wpforms-form-setup-content' )
|
||||
.on( 'keyup', '#wpforms-setup-template-search', _.debounce( WPFormsFormTemplates.searchTemplate, 200 ) )
|
||||
.on( 'click', '.wpforms-setup-templates-categories li div', WPFormsFormTemplates.selectCategory )
|
||||
.on( 'click', '.wpforms-setup-templates-categories li .chevron', WPFormsFormTemplates.toggleSubcategoriesList )
|
||||
.on( 'click', '.wpforms-setup-templates-subcategories li', WPFormsFormTemplates.selectSubCategory )
|
||||
.on( 'click', '.wpforms-template-select', app.selectTemplate )
|
||||
.on( 'click', '.wpforms-trigger-blank', app.selectBlankTemplate )
|
||||
.on( 'click', '.wpforms-template-generate', app.openAIFormGenerator );
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the AI Form Generator.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
*/
|
||||
openAIFormGenerator( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
const $button = $( this );
|
||||
|
||||
// Don't do anything for inactive button.
|
||||
if ( $button.hasClass( 'wpforms-inactive wpforms-help-tooltip' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.location = wpforms_admin_form_templates.openAIFormUrl;
|
||||
},
|
||||
|
||||
/**
|
||||
* Select template.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @param {Object} event Event object.
|
||||
*/
|
||||
selectTemplate( event ) {
|
||||
event.preventDefault();
|
||||
|
||||
const $button = $( this );
|
||||
const spinner = '<i class="wpforms-loading-spinner wpforms-loading-white wpforms-loading-inline"></i>';
|
||||
|
||||
// Don't do anything for templates that trigger education modal OR addons-modal.
|
||||
if ( $button.hasClass( 'education-modal' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// User templates are applied differently for new forms.
|
||||
if ( $button.data( 'template' ).match( /wpforms-user-template-(\d+)/ ) && $button.data( 'create-url' ) ) {
|
||||
window.location.href = $button.data( 'create-url' );
|
||||
return;
|
||||
}
|
||||
|
||||
$( '.wpforms-form-setup-content' ).find( '.wpforms-template' ).removeClass( 'active' );
|
||||
$button.closest( '.wpforms-template' ).addClass( 'active' );
|
||||
|
||||
// Save the original label.
|
||||
$button.data( 'labelOriginal', $button.html() );
|
||||
|
||||
// Display loading indicator.
|
||||
$button.html( spinner + wpforms_admin.loading );
|
||||
|
||||
WPFormsFormTemplates.selectTemplateProcess( $button.data( 'template-name-raw' ), $button.data( 'template' ), $button, app.selectTemplateProcessAjax );
|
||||
},
|
||||
|
||||
/**
|
||||
* Select Blank template.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
*/
|
||||
selectBlankTemplate( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
app.selectTemplateProcessAjax( 'Blank Form', 'blank' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Select template. Create or update form AJAX call.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @param {string} formName Name of the form.
|
||||
* @param {string} template Template slug.
|
||||
*/
|
||||
selectTemplateProcessAjax( formName, template ) {
|
||||
const data = {
|
||||
title: formName,
|
||||
action: 'wpforms_new_form',
|
||||
template,
|
||||
// eslint-disable-next-line camelcase
|
||||
form_id: 0,
|
||||
nonce: wpforms_admin_form_templates.nonce,
|
||||
};
|
||||
|
||||
const category = $( '.wpforms-setup-templates-categories li.active' ).data( 'category' );
|
||||
|
||||
if ( category && category !== 'all' ) {
|
||||
data.category = category;
|
||||
}
|
||||
|
||||
const subcategory = $( '.wpforms-setup-templates-subcategories li.active' ).data( 'subcategory' );
|
||||
|
||||
if ( subcategory ) {
|
||||
data.subcategory = subcategory;
|
||||
}
|
||||
|
||||
$.post( wpforms_admin.ajax_url, data )
|
||||
.done( function( res ) {
|
||||
if ( res.success ) {
|
||||
window.location.href = res.data.redirect;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( res.data.error_type === 'invalid_template' ) {
|
||||
app.selectTemplateProcessInvalidTemplateError( res.data.message, formName );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
app.selectTemplateProcessError( res.data.message );
|
||||
} )
|
||||
.fail( function() {
|
||||
app.selectTemplateProcessError( '' );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Select template AJAX call error modal for invalid template using.
|
||||
*
|
||||
* @since 1.7.7
|
||||
*
|
||||
* @param {string} errorMessage Error message.
|
||||
* @param {string} formName Name of the form.
|
||||
*/
|
||||
selectTemplateProcessInvalidTemplateError( errorMessage, formName ) {
|
||||
$.alert( {
|
||||
title: wpforms_admin.heads_up,
|
||||
content: errorMessage,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_admin.use_default_template,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action() {
|
||||
app.selectTemplateProcessAjax( formName, 'simple-contact-form-template' );
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_admin.cancel,
|
||||
action() {
|
||||
WPFormsFormTemplates.selectTemplateCancel();
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Select template AJAX call error modal.
|
||||
*
|
||||
* @since 1.7.7
|
||||
* @since 1.8.8 Replaced error message with error title.
|
||||
*
|
||||
* @param {string} errorTitle Error title.
|
||||
*/
|
||||
selectTemplateProcessError( errorTitle ) {
|
||||
$.alert( {
|
||||
title: errorTitle,
|
||||
content: wpforms_admin.error_select_template,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_admin.ok,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action() {
|
||||
WPFormsFormTemplates.selectTemplateCancel();
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPFormsAdminFormTemplates.init();
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user