Initial commit: Atomaste website
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 ) );
|
||||
@@ -0,0 +1 @@
|
||||
!function(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();
|
||||
@@ -0,0 +1 @@
|
||||
"use strict";var WPFormsAdminNotifications=window.WPFormsAdminNotifications||function(t){var i={$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")},a={init:function(){t(a.ready)},ready:function(){a.updateNavigation(),a.events()},events:function(){i.$notifications.on("click",".dismiss",a.dismiss).on("click",".next",a.navNext).on("click",".prev",a.navPrev)},dismiss:function(e){var n,s;0!==i.$currentMessage.length&&(1<(s=parseInt(i.$adminBarCounter.text(),10))?i.$adminBarCounter.html(--s):(i.$adminBarCounter.remove(),i.$adminBarMenuItem.remove()),s=i.$nextMessage.length<1?i.$prevMessage:i.$nextMessage,n=i.$currentMessage.data("message-id"),0===s.length?i.$notifications.remove():(i.$currentMessage.remove(),s.addClass("current"),a.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){i.$nextButton.hasClass("disabled")||(i.$currentMessage.removeClass("current"),i.$nextMessage.addClass("current"),a.updateNavigation())},navPrev:function(e){i.$prevButton.hasClass("disabled")||(i.$currentMessage.removeClass("current"),i.$prevMessage.addClass("current"),a.updateNavigation())},updateNavigation:function(){i.$currentMessage=i.$notifications.find(".wpforms-notifications-message.current"),i.$nextMessage=i.$currentMessage.next(".wpforms-notifications-message"),i.$prevMessage=i.$currentMessage.prev(".wpforms-notifications-message"),0===i.$nextMessage.length?i.$nextButton.addClass("disabled"):i.$nextButton.removeClass("disabled"),0===i.$prevMessage.length?i.$prevButton.addClass("disabled"):i.$prevButton.removeClass("disabled")}};return a}((document,window,jQuery));WPFormsAdminNotifications.init();
|
||||
File diff suppressed because it is too large
Load Diff
1
Atomaste Reference/public_html/wp-content/plugins/wpforms-lite/assets/js/admin/admin.min.js
vendored
Normal file
1
Atomaste Reference/public_html/wp-content/plugins/wpforms-lite/assets/js/admin/admin.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,595 @@
|
||||
/* global wpforms_builder_providers, wpforms_builder, wpf, WPForms */
|
||||
|
||||
( 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 );
|
||||
} );
|
||||
|
||||
$( document ).on( 'wpformsPanelSwitch', function( e, targetPanel ) {
|
||||
WPFormsProviders.providerPanelConfirm( targetPanel );
|
||||
} );
|
||||
|
||||
// Alert users if they save a form and do not configure required
|
||||
// fields.
|
||||
$( document ).on( 'wpformsSaved', function() {
|
||||
|
||||
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 ( wpf.savedState != wpf.getFormState( '#wpforms-builder-form' ) ) {
|
||||
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 providerClass = WPFormsProviders.getProviderClass( provider );
|
||||
|
||||
// Check if the provider has a method to set the custom connection name.
|
||||
if ( typeof providerClass?.setDefaultModalValue === 'function' ) {
|
||||
return providerClass.setDefaultModalValue();
|
||||
}
|
||||
|
||||
const providerName = $( `#${ provider }-provider` ).data( 'provider-name' );
|
||||
const numberOfConnections = WPFormsProviders.getCountConnectionsOf( provider );
|
||||
const defaultName = `${ providerName } ${ wpforms_builder.connection_label }`;
|
||||
|
||||
if ( numberOfConnections === 0 ) {
|
||||
return defaultName;
|
||||
}
|
||||
|
||||
return `${ defaultName } #${ numberOfConnections + 1 }`;
|
||||
},
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @param {string} provider Provider name.
|
||||
*
|
||||
* @return {Object|null} Return provider object or null.
|
||||
*/
|
||||
getProviderClass( provider ) {
|
||||
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 );
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,716 @@
|
||||
// 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;
|
||||
}
|
||||
|
||||
const isModified = wpf.savedState !== wpf.getFormState( '#wpforms-builder-form' );
|
||||
|
||||
// The form was changed and must be saved before following the action URL.
|
||||
if ( isModified ) {
|
||||
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();
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,790 @@
|
||||
/* 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 );
|
||||
},
|
||||
|
||||
/**
|
||||
* Disable drag & drop.
|
||||
*
|
||||
* @since 1.7.1
|
||||
* @since 1.7.7 Moved from admin-builder.js.
|
||||
*/
|
||||
disableDragAndDrop() {
|
||||
el.$addFieldsButtons.filter( '.ui-draggable' ).draggable( 'disable' );
|
||||
el.$sortableFieldsWrap.sortable( 'disable' );
|
||||
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 );
|
||||
|
||||
el.$builder.find( '.wpforms-layout-column' ).each( function() {
|
||||
app.initSortableContainer( $( this ) );
|
||||
} );
|
||||
|
||||
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.
|
||||
*/
|
||||
initSortableContainer( $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;
|
||||
|
||||
// noinspection JSUnresolvedReference
|
||||
$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();
|
||||
|
||||
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( function( index, className ) {
|
||||
// Remove all classes starting with `wpforms-field-drag-to-column`.
|
||||
return ( className.match( /wpforms-field-drag-to-column(-\d+|)/g ) || [] ).join( ' ' );
|
||||
} );
|
||||
|
||||
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 );
|
||||
|
||||
fieldId = $field.data( 'field-id' );
|
||||
fieldType = $field.data( 'field-type' ) || vars.fieldType;
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
const isNewField = typeof fieldId === 'undefined',
|
||||
isColumn = $sortable.hasClass( 'wpforms-layout-column' );
|
||||
|
||||
// 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();
|
||||
|
||||
$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;
|
||||
}
|
||||
);
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* 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();
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,287 @@
|
||||
/**
|
||||
* 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.
|
||||
button: $( '.button' ), // Button.
|
||||
buttonDistance: 21, // Distance from dropdown to the button.
|
||||
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' );
|
||||
},
|
||||
} );
|
||||
*/
|
||||
|
||||
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,
|
||||
button: null,
|
||||
buttonDistance: 10,
|
||||
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' );
|
||||
|
||||
/**
|
||||
* Close the dropdown.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*/
|
||||
self.close = function() {
|
||||
self.$el.addClass( 'closed' );
|
||||
};
|
||||
|
||||
/**
|
||||
* Open the dropdown.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*/
|
||||
self.open = function() {
|
||||
self.$el.removeClass( 'closed' );
|
||||
self.setPosition();
|
||||
|
||||
// Close dropdown on click outside.
|
||||
self.$builder.on( 'click.DropdowmList', function( e ) {
|
||||
const $target = $( e.target );
|
||||
|
||||
if ( $target.closest( self.$el ).length || $target.hasClass( 'button-insert-field' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.$builder.off( 'click.DropdowmList' );
|
||||
|
||||
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.
|
||||
const items = [];
|
||||
|
||||
for ( const i in list ) {
|
||||
items.push( `<li data-value="${ list[ i ].value }">${ itemFormat( list[ i ] ) }</li>` );
|
||||
}
|
||||
|
||||
return `<div class="wpforms-builder-dropdown-list closed ${ self.options.class }">
|
||||
<div class="title">${ self.options.title }</div>
|
||||
<ul>${ items.join( '' ) }</ul>
|
||||
</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;
|
||||
|
||||
// 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 needed 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.css( 'top', top );
|
||||
|
||||
// The dropdown is outside the field options, it is needed 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 );
|
||||
|
||||
self.options.onSelect( event, $item.data( 'value' ), $item.text(), $item, self );
|
||||
} );
|
||||
};
|
||||
|
||||
/**
|
||||
* 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();
|
||||
};
|
||||
|
||||
// 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 ) );
|
||||
@@ -0,0 +1,4 @@
|
||||
var WPForms=window.WPForms||{};WPForms.Admin=WPForms.Admin||{},WPForms.Admin.Builder=WPForms.Admin.Builder||{},WPForms.Admin.Builder.DropdownList=WPForms.Admin.Builder.DropdownList||function(n){function o(t){const s=this,i={class:"",title:"",list:[],container:null,scrollableContainer:null,button:null,buttonDistance:10,onSelect:null,itemFormat(t){return t.text}};s.options=n.extend(i,t),s.$el=null,s.$builder=n("#wpforms-builder"),s.close=function(){s.$el.addClass("closed")},s.open=function(){s.$el.removeClass("closed"),s.setPosition(),s.$builder.on("click.DropdowmList",function(t){var t=n(t.target);t.closest(s.$el).length||t.hasClass("button-insert-field")||(s.$builder.off("click.DropdowmList"),(t=n(s.options.button)).hasClass("active")&&t.trigger("click"))})},s.generateHtml=function(){var t=s.options.list;if(!t||0===t.length)return"";var o=("function"==typeof s.options.itemFormat?s.options:i).itemFormat,n=[];for(const e in t)n.push(`<li data-value="${t[e].value}">${o(t[e])}</li>`);return`<div class="wpforms-builder-dropdown-list closed ${s.options.class}">
|
||||
<div class="title">${s.options.title}</div>
|
||||
<ul>${n.join("")}</ul>
|
||||
</div>`},s.attach=function(){var t=s.generateHtml();s.$el&&s.$el.length&&s.$el.remove(),s.$el=n(t),s.$button=n(s.options.button),s.$container=s.options.container?n(s.options.container):s.$button.parent(),s.$scrollableContainer=s.options.scrollableContainer?n(s.options.scrollableContainer):null,s.$container.append(s.$el),s.setPosition()},s.setPosition=function(){var t=s.$button.offset(),o=s.$container.offset(),n=s.$container.position(),e=s.$el.height(),i=s.$scrollableContainer?s.$scrollableContainer.scrollTop():0;let l=t.top-o.top-e-s.options.buttonDistance;i+n.top-e<0&&(l=t.top-o.top+s.$button.height()+s.options.buttonDistance-11),s.$el.css("top",l),0===s.$container.closest(".wpforms-field-option").length&&s.$el.css("left",t.left-o.left)},s.events=function(){s.$el.find("li").off().on("click",function(t){var o;"function"==typeof s.options.onSelect&&(o=n(this),s.options.onSelect(t,o.data("value"),o.text(),o,s))})},s.init=function(t=null){s.options.list=t||s.options.list,s.attach(),s.events(),s.$button.data("dropdown-list",s)},s.destroy=function(){s.$button.data("dropdown-list",null),s.$el.remove()},s.init()}return{init(t){return new o(t)}}}((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();
|
||||
@@ -0,0 +1 @@
|
||||
var WPFormsBuilderEmailTemplate=window.WPFormsBuilderEmailTemplate||function(e,m,n){const s={},d={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(){s.$document=m(e),s.$body=m("body")},bindEvents(){s.$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&&d.modal&&(a=m(this).val(),e.val(a).trigger("change"),d.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}),d.modal=m.confirm({content:o,title:"",boxWidth:800,contentMaxHeight:"none",backgroundDismiss:!0,smoothContent:!1,closeIcon:!0,buttons:!1,onOpenBefore(){this.$body.addClass(d.classNames.modalBox),s.$body.addClass(d.classNames.modalOpen)},onClose(){s.$body.removeClass(d.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,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();
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,282 @@
|
||||
/* 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,
|
||||
|
||||
/**
|
||||
* 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-group .wpforms-numbers-min',
|
||||
app.onChangeNumbersMin
|
||||
);
|
||||
|
||||
app.$builder.on(
|
||||
'change',
|
||||
'.wpforms-field-option-group .wpforms-numbers-max',
|
||||
app.onChangeNumbersMax
|
||||
);
|
||||
|
||||
app.$builder.on(
|
||||
'change',
|
||||
'.wpforms-field-option-group .wpforms-field-option-row-default_value input',
|
||||
app.onChangeNumbersDefaultValue
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* 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' );
|
||||
},
|
||||
|
||||
/**
|
||||
* 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' );
|
||||
|
||||
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' );
|
||||
|
||||
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 ) {
|
||||
const $defaultValueField = $( event.target ),
|
||||
$container = $defaultValueField.closest( '.wpforms-field-option-group' ),
|
||||
$minField = $container.find( '.wpforms-numbers-min' ),
|
||||
$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();
|
||||
@@ -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||function(r){const l={$builder:null,init(){r(l.ready)},ready(){l.$builder=r("#wpforms-builder"),l.numbersEvents()},numbersEvents(){l.$builder.on("change",".wpforms-field-option-group .wpforms-numbers-min",l.onChangeNumbersMin),l.$builder.on("change",".wpforms-field-option-group .wpforms-numbers-max",l.onChangeNumbersMax),l.$builder.on("change",".wpforms-field-option-group .wpforms-field-option-row-default_value input",l.onChangeNumbersDefaultValue)},parseFieldValue(e){return!e.length||""===e.val()||(e=parseFloat(e.val()),isNaN(e))?null:e},isInvalidMinMaxRange(e,u){e=l.parseFieldValue(e),u=l.parseFieldValue(u);return null!==e&&null!==u&&u<e},syncNumberMinAttribute(e,u){u.attr("min",l.parseFieldValue(e))},syncNumberMaxAttribute(e,u){e.attr("max",l.parseFieldValue(u))},adjustValue(e,u){u.val(l.parseFieldValue(e)).trigger("input")},onChangeNumbersMin(e){var e=r(e.target),u=e.closest(".wpforms-field-option-group"),a=u.find(".wpforms-numbers-max"),u=u.find(".wpforms-field-option-row-default_value input");l.isInvalidMinMaxRange(e,a)&&l.adjustValue(a,e),l.isNeedAdjustDefaultValueByMinValue(u,e)&&l.adjustValue(e,u),l.syncNumberMinAttribute(e,a)},onChangeNumbersMax(e){var e=r(e.target),u=e.closest(".wpforms-field-option-group"),a=u.find(".wpforms-numbers-min"),u=u.find(".wpforms-field-option-row-default_value input");l.isInvalidMinMaxRange(a,e)&&l.adjustValue(a,e),l.isNeedAdjustDefaultValueByMaxValue(u,e)&&l.adjustValue(e,u),l.syncNumberMaxAttribute(a,e)},normalizeFloatValue(e){var u=e.val(),a=u.replace(",",".");wpf.isNumber(a)&&u!==parseFloat(u).toString()&&e.val(parseFloat(a)).trigger("input")},isNeedAdjustDefaultValueByMinValue(e,u){e=l.parseFieldValue(e),u=l.parseFieldValue(u);return wpf.isNumber(e)&&null!==u&&e<u},isNeedAdjustDefaultValueByMaxValue(e,u){e=l.parseFieldValue(e),u=l.parseFieldValue(u);return wpf.isNumber(e)&&null!==u&&u<e},onChangeNumbersDefaultValue(e){var e=r(e.target),u=e.closest(".wpforms-field-option-group"),a=u.find(".wpforms-numbers-min"),u=u.find(".wpforms-numbers-max");l.normalizeFloatValue(e),l.isNeedAdjustDefaultValueByMinValue(e,a)&&l.adjustValue(a,e),l.isNeedAdjustDefaultValueByMaxValue(e,u)&&l.adjustValue(u,e)}};return l}((document,window,jQuery)),WPForms.Admin.Builder.FieldNumbers.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();
|
||||
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: $( '#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();
|
||||
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();
|
||||
@@ -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||function(n){const 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();
|
||||
File diff suppressed because it is too large
Load Diff
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();
|
||||
@@ -0,0 +1 @@
|
||||
"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(e,o){const 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");const 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,330 @@
|
||||
/* global wpforms_builder_settings, Choices, wpf */
|
||||
|
||||
// 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' ),
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 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 );
|
||||
},
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
app.toggleFilteringMessages( ! $( this ).prop( 'checked' ) && $( '#wpforms-panel-field-settings-store_spam_entries' ).prop( 'checked' ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* 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 );
|
||||
|
||||
// Update form state when hidden input initialized.
|
||||
// This will prevent a please-save-prompt to appear when switching from revisions without doing any changes anywhere.
|
||||
if ( wpf.initialSave === true ) {
|
||||
wpf.savedState = wpf.getFormState( '#wpforms-builder-form' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 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 )
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPForms.Admin.Builder.Settings.init();
|
||||
@@ -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||function(t,i){let a={};const n={};var l={init(){i(l.ready)},ready(){l.setup(),l.initTags(),l.events()},setup(){a={$builder:i("#wpforms-builder"),$panel:i("#wpforms-panel-settings"),$selectTags:i("#wpforms-panel-field-settings-form_tags")}},events(){a.$panel.on("keydown","#wpforms-panel-field-settings-form_tags-wrap input",l.addCustomTagInput).on("removeItem","#wpforms-panel-field-settings-form_tags-wrap select",l.editTagsRemoveItem).on("change","#wpforms-panel-field-settings-antispam_v3",l.enableAntispamV3).on("change","#wpforms-panel-field-settings-disable_entries",l.disableEntries).on("change","#wpforms-panel-field-settings-store_spam_entries",l.storeSpamEntries),a.$selectTags.on("change",l.changeTags)},enableAntispamV3(){i("#wpforms-panel-field-settings-antispam").prop("checked",!1).closest(".wpforms-panel-field").toggleClass("wpforms-hidden")},disableEntries(){l.toggleFilteringMessages(!i(this).prop("checked")&&i("#wpforms-panel-field-settings-store_spam_entries").prop("checked"))},storeSpamEntries(){l.toggleFilteringMessages(i(this).prop("checked"))},toggleFilteringMessages(e){i("#wpforms-panel-field-anti_spam-filtering_store_spam").is(":checked")&&(i("#wpforms-panel-field-anti_spam-country_filter-message-wrap").toggleClass("wpforms-hidden",e),i("#wpforms-panel-field-anti_spam-keyword_filter-message-wrap").toggleClass("wpforms-hidden",e))},initTags(e=null){var s;(e=e?.length?e:a.$selectTags).length&&"function"==typeof t.Choices&&(n.tagsChoicesObj=new Choices(e[0],wpforms_builder_settings.choicesjs_config),s=n.tagsChoicesObj.getValue(!0),n.tagsChoicesObj.clearStore().setChoices(wpforms_builder_settings.all_tags_choices,"value","label",!0).setChoiceByValue(s),e.data("choicesjs",n.tagsChoicesObj),l.initTagsHiddenInput())},initTagsHiddenInput(){a.$selectTagsHiddenInput=i('<input type="hidden" name="settings[form_tags_json]">'),a.$selectTags.closest(".wpforms-panel-field").append(a.$selectTagsHiddenInput),l.changeTags(null),!0===wpf.initialSave&&(wpf.savedState=wpf.getFormState("#wpforms-builder-form"))},addCustomTagInput(e){var s,t;["Enter",","].indexOf(e.key)<0||(e.preventDefault(),e.stopPropagation(),n.tagsChoicesObj&&0!==e.target.value.length&&(s=_.escape(e.target.value).trim(),t=_.map(n.tagsChoicesObj.getValue(),"label").map(function(e){return e.toLowerCase().trim()}),""===s||0<=t.indexOf(s.toLowerCase())?n.tagsChoicesObj.clearInput():(l.addCustomTagInputCreate(s),l.changeTags(e))))},editTagsRemoveItem(s){var e,t,a;0<=_.map(wpforms_builder_settings.all_tags_choices,"value").indexOf(s.detail.value)||(t=(e=i(s.target).data("choicesjs")).getValue(!0),a=_.filter(e._currentState.choices,function(e){return e.value!==s.detail.value}),e.clearStore().setChoices(a,"value","label",!0).setChoiceByValue(t))},addCustomTagInputCreate(e){var s=_.find(wpforms_builder_settings.all_tags_choices,{label:e});s&&s.value?n.tagsChoicesObj.setChoiceByValue(s.value):n.tagsChoicesObj.setChoices([{value:e,label:e,selected:!0}],"value","label",!1),n.tagsChoicesObj.clearInput()},changeTags(e){var s=n.tagsChoicesObj.getValue(),t=[];for(let e=0;e<s.length;e++)t.push({value:s[e].value,label:s[e].label});a.$selectTagsHiddenInput.val(JSON.stringify(t))}};return l}((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();
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,107 @@
|
||||
/* global WPForms, jQuery, Map, wpforms_builder, wpforms_builder_providers, _ */
|
||||
|
||||
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, $ ) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Private functions and properties.
|
||||
*
|
||||
* @since 1.4.8
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var __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(),
|
||||
};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.4.8
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var app = {
|
||||
|
||||
/**
|
||||
* Start the engine. DOM is not ready yet, use only to init something.
|
||||
*
|
||||
* @since 1.4.8
|
||||
*/
|
||||
init: function() {
|
||||
|
||||
// Do that when DOM is ready.
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* DOM is fully loaded.
|
||||
*
|
||||
* @since 1.4.8
|
||||
*/
|
||||
ready: function() {
|
||||
|
||||
$( '#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: function( 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.
|
||||
*
|
||||
* @returns {*} A callable that after compiling will always return a string.
|
||||
*/
|
||||
get: function( template ) {
|
||||
|
||||
var preview = __private.previews.get( template );
|
||||
|
||||
if ( typeof preview !== 'undefined' ) {
|
||||
return preview;
|
||||
}
|
||||
|
||||
return function() {
|
||||
return '';
|
||||
};
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
|
||||
} )( document, window, jQuery );
|
||||
|
||||
// Initialize.
|
||||
WPForms.Admin.Builder.Templates.init();
|
||||
@@ -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||function(e){"use strict";var r={previews:new Map},i={init:function(){e(i.ready)},ready:function(){e("#wpforms-panel-providers").trigger("WPForms.Admin.Builder.Templates.ready")},add:function(e){e.forEach(function(e){"string"==typeof e&&r.previews.set(e,wp.template(e))})},get:function(e){e=r.previews.get(e);return void 0!==e?e:function(){return""}}};return i}((document,window,jQuery)),WPForms.Admin.Builder.Templates.init();
|
||||
@@ -0,0 +1,229 @@
|
||||
/* global wpforms_builder, Choices, wpf */
|
||||
|
||||
/**
|
||||
* WPForms ChoicesJS utility methods for the Admin Builder.
|
||||
*
|
||||
* @since 1.7.9
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var WPForms = window.WPForms || {};
|
||||
|
||||
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 = {
|
||||
|
||||
/**
|
||||
* Setup 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.
|
||||
*
|
||||
* @returns {Choices} ChoicesJS instance.
|
||||
*/
|
||||
setup: function( element, choicesJSArgs, ajaxArgs ) {
|
||||
|
||||
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;
|
||||
|
||||
const choicesJS = new Choices( element, choicesJSArgs );
|
||||
|
||||
if ( ajaxArgs.nonce === null ) {
|
||||
return choicesJS;
|
||||
}
|
||||
|
||||
$( element ).data( 'choicesjs', choicesJS );
|
||||
|
||||
/*
|
||||
* ChoicesJS doesn't handle empty string search with it's `search` event handler,
|
||||
* so we work around it by detecting empty string search with `keyup` event.
|
||||
*/
|
||||
choicesJS.input.element.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 ) );
|
||||
|
||||
choicesJS.passedElement.element.addEventListener( 'change', function() {
|
||||
const select = $( this ),
|
||||
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 ability to close the drop-down menu.
|
||||
choicesJS.containerOuter.element.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( choicesJS.containerOuter.element );
|
||||
} )
|
||||
.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();
|
||||
} );
|
||||
|
||||
return choicesJS;
|
||||
},
|
||||
|
||||
/**
|
||||
* 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 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 );
|
||||
}
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
|
||||
}( document, window, jQuery ) );
|
||||
@@ -0,0 +1 @@
|
||||
"use strict";var WPForms=window.WPForms||{};WPForms.Admin=WPForms.Admin||{},WPForms.Admin.Builder=WPForms.Admin.Builder||{},WPForms.Admin.Builder.WPFormsChoicesJS=WPForms.Admin.Builder.WPFormsChoicesJS||function(o,t){const r={setup:function(i,e,n){e.searchEnabled=!0,e.allowHTML=!1,e.searchChoices=null===n.nonce,e.renderChoiceLimit=-1,e.noChoicesText=e.noChoicesText||wpforms_builder.no_pages_found,e.noResultsText=e.noResultsText||wpforms_builder.no_pages_found;const a=new Choices(i,e);return null!==n.nonce&&(t(i).data("choicesjs",a),a.input.element.addEventListener("keyup",function(e){8!==e.which&&46!==e.which||0<e.target.value.length||r.performSearch(a,"",n)}),a.passedElement.element.addEventListener("search",_.debounce(function(e){0!==a.input.element.value.length&&r.performSearch(a,e.detail.value,n)},800)),a.passedElement.element.addEventListener("change",function(){var e=t(this),n=e.data("field-id"),e=e.data("field-name"),o=a.getValue().map(function(e){return e.value});t(`#wpforms-field-${n}-${e}-select-multiple-options`).val(JSON.stringify(o))}),a.containerOuter.element.addEventListener("click",function(){t(this).hasClass("is-open")&&a.hideDropdown()}),t(o).on("wpformsFieldOptionGroupToggled",function(){wpf.showMoreButtonForChoices(a.containerOuter.element)}).on("wpformsBeforeFieldDuplicate",function(e,n){if(t(i).data("field-id")===n){const o=a.getValue(!0);t(i).data("choicesjs").destroy(),t(i).find("option").each(function(e,n){o.includes(t(n).val())&&t(n).prop("selected",!0)})}}).on("wpformsFieldDuplicated",function(e,n){t(i).data("field-id")===n&&t(i).data("choicesjs").init()})),a},performSearch(n,e,o){o.action&&o.nonce&&(r.displayLoading(n),r.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."),r.ajaxSearch(e,n,o)},ajaxSearch(e,n,o,i=[]){return t.get(wpforms_builder.ajax_url,{action:e,search:n,_wpnonce:o,exclude:i}).fail(function(e){console.error(e)})}};return r}(document,(window,jQuery));
|
||||
@@ -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();
|
||||
@@ -0,0 +1 @@
|
||||
"use strict";var WPFormsChallenge=window.WPFormsChallenge||{};WPFormsChallenge.admin=window.WPFormsChallenge.admin||function(o){var l={l10n:wpforms_challenge_admin,init:function(){o(l.ready)},ready:function(){l.events()},events:function(){o(".wpforms-challenge-list-block").on("click",".challenge-skip",l.skipChallenge).on("click",".challenge-cancel",l.cancelChallenge).on("click",".toggle-list",l.toggleList)},toggleList:function(e){var e=o(e.target),n=o(".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*l.l10n.minutes_left};o(".wpforms-challenge").remove(),o("#wpforms-embed").removeClass("wpforms-disabled"),l.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(o("#wpforms-challenge-admin-js, #wpforms-challenge-core-js, #wpforms-challenge-admin-js-extra, #wpforms-challenge-builder-js").remove()):WPFormsChallenge.admin.saveChallengeOption(n).done(l.triggerPageSave)},saveChallengeOption:function(e){var n={action:"wpforms_challenge_save_option",option_data:e,_wpnonce:l.l10n.nonce};return n.option_data.window_closed=wpforms_challenge_admin.option.window_closed,o.extend(wpforms_challenge_admin.option,e),o.post(ajaxurl,n,function(e){e.success||console.error("Error saving WPForms Challenge option.")})}};return l}((document,window,jQuery)),WPFormsChallenge.admin.init();
|
||||
@@ -0,0 +1,286 @@
|
||||
/* 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 );
|
||||
|
||||
// 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();
|
||||
@@ -0,0 +1 @@
|
||||
"use strict";var WPFormsChallenge=window.WPFormsChallenge||{};WPFormsChallenge.builder=window.WPFormsChallenge.builder||function(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.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();
|
||||
@@ -0,0 +1,920 @@
|
||||
/* global wpforms_challenge_admin */
|
||||
/**
|
||||
* 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: function( step, anchor, args ) {
|
||||
|
||||
if ( typeof $.fn.tooltipster === 'undefined' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var $dot = $( '<span class="wpforms-challenge-dot wpforms-challenge-dot-step' + step + '" data-wpforms-challenge-step="' + step + '"> </span>' );
|
||||
var tooltipsterArgs = {
|
||||
content : $( '#tooltip-content' + step ),
|
||||
trigger : null,
|
||||
interactive : true,
|
||||
animationDuration: 0,
|
||||
delay : 0,
|
||||
theme : [ 'tooltipster-default', 'wpforms-challenge-tooltip' ],
|
||||
side : [ 'top' ],
|
||||
distance : 3,
|
||||
functionReady : function( instance, helper ) {
|
||||
|
||||
$( helper.tooltip ).addClass( 'wpforms-challenge-tooltip-step' + step );
|
||||
|
||||
// Custom positioning.
|
||||
if ( step === 4 || step === 3 ) {
|
||||
instance.option( 'side', 'right' );
|
||||
} else if ( step === 1 ) {
|
||||
instance.option( 'side', '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
|
||||
*
|
||||
* @param {object} e Event object.
|
||||
*/
|
||||
refreshPage: function( e ) {
|
||||
|
||||
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();
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,323 @@
|
||||
/* 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: function() {
|
||||
|
||||
// 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() ) {
|
||||
WPFormsChallenge.core.initTooltips( 5, '.block-editor .edit-post-header', { side: 'bottom' } );
|
||||
app.updateTooltipVisibility();
|
||||
} 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' );
|
||||
} );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPFormsChallenge.embed.init();
|
||||
@@ -0,0 +1 @@
|
||||
"use strict";var WPFormsChallenge=window.WPFormsChallenge||{};WPFormsChallenge.embed=window.WPFormsChallenge.embed||function(o,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:function(){-1<e.location.href.indexOf("post-new.php")?(t.lastStep(),c(".wpforms-challenge-dot-completed").hide()):(WPFormsChallenge.core.isGutenberg()?(WPFormsChallenge.core.initTooltips(5,".block-editor .edit-post-header",{side:"bottom"}),t.updateTooltipVisibility()):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=o.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")})}};return t}(document,window,jQuery),WPFormsChallenge.embed.init();
|
||||
@@ -0,0 +1,758 @@
|
||||
/* 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.4.2
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* @param {Event} event Event.
|
||||
*/
|
||||
openModalButtonHandler( event ) {
|
||||
event.preventDefault();
|
||||
|
||||
const $this = $( 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;
|
||||
}
|
||||
|
||||
// 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,
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* 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,
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* 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,
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* 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,
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* 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();
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,396 @@
|
||||
/* 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, $ ) {
|
||||
/**
|
||||
* 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,
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
load() {
|
||||
if ( ! app.isGutenbergEditor() ) {
|
||||
app.maybeShowClassicNotice();
|
||||
app.bindClassicEvents();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const blockLoadedInterval = setInterval( function() {
|
||||
if ( ! document.querySelector( '.editor-post-title__input, iframe[name="editor-canvas"]' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearInterval( blockLoadedInterval );
|
||||
|
||||
if ( ! app.isFse() ) {
|
||||
app.maybeShowGutenbergNotice();
|
||||
app.bindGutenbergEvents();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const iframe = document.querySelector( 'iframe[name="editor-canvas"]' );
|
||||
const observer = new MutationObserver( function() {
|
||||
const iframeDocument = iframe.contentDocument || iframe.contentWindow.document || {};
|
||||
|
||||
if ( iframeDocument.readyState === 'complete' && iframeDocument.querySelector( '.editor-post-title__input' ) ) {
|
||||
app.maybeShowGutenbergNotice();
|
||||
app.bindFseEvents();
|
||||
|
||||
observer.disconnect();
|
||||
}
|
||||
} );
|
||||
observer.observe( document.body, { subtree: true, childList: true } );
|
||||
}, 200 );
|
||||
},
|
||||
|
||||
/**
|
||||
* 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 );
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events for Gutenberg Editor.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
bindGutenbergEvents() {
|
||||
const $document = $( document );
|
||||
|
||||
$document
|
||||
.on( 'DOMSubtreeModified', '.edit-post-layout', app.distractionFreeModeToggle );
|
||||
|
||||
if ( app.isNoticeVisible ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$document
|
||||
.on( 'input', '.editor-post-title__input', _.debounce( app.maybeShowGutenbergNotice, 1000 ) )
|
||||
.on( 'DOMSubtreeModified', '.editor-post-title__input', _.debounce( app.maybeShowGutenbergNotice, 1000 ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events for Gutenberg Editor in FSE mode.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
bindFseEvents() {
|
||||
const $iframe = $( 'iframe[name="editor-canvas"]' );
|
||||
|
||||
$( document )
|
||||
.on( 'DOMSubtreeModified', '.edit-post-layout', app.distractionFreeModeToggle );
|
||||
|
||||
$iframe.contents()
|
||||
.on( 'input', '.editor-post-title__input', _.debounce( app.maybeShowGutenbergNotice, 1000 ) )
|
||||
.on( 'DOMSubtreeModified', '.editor-post-title__input', _.debounce( app.maybeShowGutenbergNotice, 1000 ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* 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';
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine if the editor is Gutenberg in FSE mode.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @return {boolean} True if the Gutenberg editor in FSE mode.
|
||||
*/
|
||||
isFse() {
|
||||
return Boolean( $( 'iframe[name="editor-canvas"]' ).length );
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a notice for Gutenberg.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
showGutenbergNotice() {
|
||||
wp.data.dispatch( 'core/notices' ).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 pluginName = 'wpforms-edit-post-product-education-guide';
|
||||
const noticeSettings = {
|
||||
id: pluginName,
|
||||
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.Guide;
|
||||
const useState = wp.element.useState;
|
||||
const registerPlugin = wp.plugins.registerPlugin;
|
||||
const unregisterPlugin = wp.plugins.unregisterPlugin;
|
||||
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( pluginName );
|
||||
setIsOpen( false );
|
||||
} }
|
||||
pages={ app.getGuidePages() }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
noticeSettings.actions[ 0 ].onClick = () => registerPlugin( pluginName, { 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 $postTitle = app.isFse()
|
||||
? $( 'iframe[name="editor-canvas"]' ).contents().find( '.editor-post-title__input' )
|
||||
: $( '.editor-post-title__input' );
|
||||
const tagName = $postTitle.prop( 'tagName' );
|
||||
const title = tagName === 'TEXTAREA' ? $postTitle.val() : $postTitle.text();
|
||||
|
||||
if ( app.isTitleMatchKeywords( title ) ) {
|
||||
app.isNoticeVisible = true;
|
||||
|
||||
app.showGutenbergNotice();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add notice class when the distraction mode is enabled.
|
||||
*
|
||||
* @since 1.8.1.2
|
||||
*/
|
||||
distractionFreeModeToggle() {
|
||||
if ( ! app.isNoticeVisible ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $document = $( document );
|
||||
const isDistractionFreeMode = Boolean( $document.find( '.is-distraction-free' ).length );
|
||||
|
||||
if ( ! isDistractionFreeMode ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isNoticeHasClass = Boolean( $( '.wpforms-edit-post-education-notice' ).length );
|
||||
|
||||
if ( isNoticeHasClass ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $noticeBody = $document.find( '.wpforms-edit-post-education-notice-body' );
|
||||
const $notice = $noticeBody.closest( '.components-notice' );
|
||||
|
||||
$notice.addClass( 'wpforms-edit-post-education-notice' );
|
||||
},
|
||||
|
||||
/**
|
||||
* 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,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();
|
||||
@@ -0,0 +1 @@
|
||||
var WPFormsPointersPayment=window.WPFormsPointersPayment||function(n,t,o,e){const i={},r={pointerId:e.pointer,nonce:e.nonce},a={init(){o(a.ready)},ready(){a.setup(),a.bindEvents()},setup(){i.$document=o(n)},bindEvents(){i.$document.on("click",'#toplevel_page_wpforms-overview [href$="-payments"], #wpforms-education-pointers-payments',a.handleOnClick)},handleOnClick(n){n.preventDefault();n=o(this);const e=n.attr("href");e&&(n.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=e}))}};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();
|
||||
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();
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
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();
|
||||
@@ -0,0 +1 @@
|
||||
const WPFormsLogger=window.WPFormsLogger||function(n,t){const s={init(){t(s.ready)},ready(){s.bindEvents()},bindPopup(){t(".wpforms-list-table--logs .wp-list-table").on("click",".js-single-log-target",function(o){o.preventDefault(),s.showPopup(t(this).attr("data-log-id"))})},bindEvents(){s.bindPopup(),t("#wpforms-setting-logs-enable").change(function(){s.toggleLogs(t(this).is(":checked"))})},toggleLogs(o){t(".wpforms-logs-settings").toggleClass("wpforms-hidden",!o)},showPopup(o){if(o){const e=wp.template("wpforms-log-record");t.dialog({title:!1,boxWidth:Math.min(1200,.8*t(n).width()),content(){const n=this;return t.get(wpforms_admin.ajax_url,{action:"wpforms_get_log_record",nonce:wpforms_admin.nonce,recordId:o}).done(function(o){o.success&&o.data?n.setContent(e(o.data)):(s.error(o.data),n.close())}).fail(function(o,e){s.error(e+" "+o.responseText),n.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,89 @@
|
||||
/* global wpforms_admin_notices */
|
||||
|
||||
/**
|
||||
* WPForms Dismissible Notices.
|
||||
*
|
||||
* @since 1.6.7.1
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
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: function() {
|
||||
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.6.7.1
|
||||
*/
|
||||
ready: function() {
|
||||
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Dismissible notices events.
|
||||
*
|
||||
* @since 1.6.7.1
|
||||
*/
|
||||
events: function() {
|
||||
|
||||
$( 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: function( 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();
|
||||
@@ -0,0 +1 @@
|
||||
"use strict";var WPFormsAdminNotices=window.WPFormsAdminNotices||function(i,s){var o={init:function(){s(o.ready)},ready:function(){o.events()},events:function(){s(i).on("click",".wpforms-notice .notice-dismiss, .wpforms-notice .wpforms-notice-dismiss",o.dismissNotice)},dismissNotice:function(i){var o=s(i.target);o.hasClass("wpforms-review-out")||i.preventDefault(),o.closest(".wpforms-notice").remove(),s.post(wpforms_admin_notices.ajax_url,{action:"wpforms_notice_dismiss",nonce:wpforms_admin_notices.nonce,id:(o.closest(".wpforms-notice").attr("id")||"").replace("wpforms-notice-","")})}};return o}(document,(window,jQuery));WPFormsAdminNotices.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();
|
||||
@@ -0,0 +1 @@
|
||||
var WPFormsAdminFormTemplates=window.WPFormsAdminFormTemplates||function(s,o){const r={init(){o(r.ready)},ready(){WPFormsFormTemplates.setup(),r.events(),wpf.initTooltips()},events(){o(".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",r.selectTemplate).on("click",".wpforms-trigger-blank",r.selectBlankTemplate).on("click",".wpforms-template-generate",r.openAIFormGenerator)},openAIFormGenerator(e){e.preventDefault(),o(this).hasClass("wpforms-inactive wpforms-help-tooltip")||(s.location=wpforms_admin_form_templates.openAIFormUrl)},selectTemplate(e){e.preventDefault();e=o(this);e.hasClass("education-modal")||(e.data("template").match(/wpforms-user-template-(\d+)/)&&e.data("create-url")?s.location.href=e.data("create-url"):(o(".wpforms-form-setup-content").find(".wpforms-template").removeClass("active"),e.closest(".wpforms-template").addClass("active"),e.data("labelOriginal",e.html()),e.html('<i class="wpforms-loading-spinner wpforms-loading-white wpforms-loading-inline"></i>'+wpforms_admin.loading),WPFormsFormTemplates.selectTemplateProcess(e.data("template-name-raw"),e.data("template"),e,r.selectTemplateProcessAjax)))},selectBlankTemplate(e){e.preventDefault(),r.selectTemplateProcessAjax("Blank Form","blank")},selectTemplateProcessAjax(t,e){var e={title:t,action:"wpforms_new_form",template:e,form_id:0,nonce:wpforms_admin_form_templates.nonce},a=o(".wpforms-setup-templates-categories li.active").data("category"),a=(a&&"all"!==a&&(e.category=a),o(".wpforms-setup-templates-subcategories li.active").data("subcategory"));a&&(e.subcategory=a),o.post(wpforms_admin.ajax_url,e).done(function(e){e.success?s.location.href=e.data.redirect:"invalid_template"===e.data.error_type?r.selectTemplateProcessInvalidTemplateError(e.data.message,t):r.selectTemplateProcessError(e.data.message)}).fail(function(){r.selectTemplateProcessError("")})},selectTemplateProcessInvalidTemplateError(e,t){o.alert({title:wpforms_admin.heads_up,content:e,icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_admin.use_default_template,btnClass:"btn-confirm",keys:["enter"],action(){r.selectTemplateProcessAjax(t,"simple-contact-form-template")}},cancel:{text:wpforms_admin.cancel,action(){WPFormsFormTemplates.selectTemplateCancel()}}}})},selectTemplateProcessError(e){o.alert({title:e,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()}}}})}};return r}((document,window),jQuery);WPFormsAdminFormTemplates.init();
|
||||
@@ -0,0 +1,259 @@
|
||||
/* global wpforms_pluginlanding, wpforms_admin */
|
||||
|
||||
/**
|
||||
* Analytics Sub-page.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var WPFormsPagesAnalytics = window.WPFormsPagesAnalytics || ( function( document, window, $ ) {
|
||||
|
||||
/**
|
||||
* Elements.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var el = {};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*/
|
||||
init: function() {
|
||||
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*/
|
||||
ready: function() {
|
||||
|
||||
app.initVars();
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Init variables.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*/
|
||||
initVars: function() {
|
||||
|
||||
el = {
|
||||
$stepInstall: $( 'section.step-install' ),
|
||||
$stepInstallNum: $( 'section.step-install .num img' ),
|
||||
$stepSetup: $( 'section.step-setup' ),
|
||||
$stepSetupNum: $( 'section.step-setup .num img' ),
|
||||
$stepAddon: $( 'section.step-addon' ),
|
||||
$stepAddonNum: $( 'section.step-addon .num img' ),
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Register JS events.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*/
|
||||
events: function() {
|
||||
|
||||
// Step 'Install' button click.
|
||||
el.$stepInstall.on( 'click', 'button', app.stepInstallClick );
|
||||
|
||||
// Step 'Setup' button click.
|
||||
el.$stepSetup.on( 'click', 'button', app.gotoURL );
|
||||
|
||||
// Step 'Addon' button click.
|
||||
el.$stepAddon.on( 'click', 'button', app.gotoURL );
|
||||
},
|
||||
|
||||
/**
|
||||
* Step 'Install' button click.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*
|
||||
*/
|
||||
stepInstallClick: function() {
|
||||
|
||||
var $btn = $( this ),
|
||||
action = $btn.attr( 'data-action' ),
|
||||
plugin = $btn.attr( 'data-plugin' ),
|
||||
ajaxAction = '';
|
||||
|
||||
if ( $btn.hasClass( 'disabled' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
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 );
|
||||
|
||||
var data = {
|
||||
action: ajaxAction,
|
||||
nonce : wpforms_admin.nonce,
|
||||
plugin: 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.5.7
|
||||
*
|
||||
* @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: function( res, $btn, action ) {
|
||||
|
||||
var success = 'install' === action ? res.success && res.data.is_activated : res.success;
|
||||
|
||||
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();
|
||||
} else {
|
||||
var activationFail = ( 'install' === action && res.success && ! res.data.is_activated ) || 'activate' === action,
|
||||
url = ! activationFail ? wpforms_pluginlanding.mi_manual_install_url : wpforms_pluginlanding.mi_manual_activate_url,
|
||||
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.5.7
|
||||
*/
|
||||
stepInstallPluginStatus: function() {
|
||||
|
||||
var data = {
|
||||
action: 'wpforms_analytics_page_check_plugin_status',
|
||||
nonce : wpforms_admin.nonce,
|
||||
};
|
||||
$.post( wpforms_admin.ajax_url, data ).done( app.stepInstallPluginStatusDone );
|
||||
},
|
||||
|
||||
/**
|
||||
* Done part of the callback for step 'Install' completion.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*
|
||||
* @param {object} res Result of $.post() query.
|
||||
*/
|
||||
stepInstallPluginStatusDone: function( 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.$stepAddon.removeClass( 'grey' );
|
||||
el.$stepAddon.find( 'button' ).attr( 'data-url', res.data.step3_button_url ).removeClass( 'grey disabled' ).addClass( 'button-primary' );
|
||||
|
||||
if ( res.data.license_level === 'pro' ) {
|
||||
var buttonText = res.data.addon_installed > 0 ? wpforms_pluginlanding.activate_now : wpforms_pluginlanding.install_now;
|
||||
el.$stepAddon.find( 'button' ).text( buttonText );
|
||||
}
|
||||
} else {
|
||||
el.$stepSetupBtn.removeClass( 'grey disabled' ).addClass( 'button-primary' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Go to URL by click on the button.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*/
|
||||
gotoURL: function() {
|
||||
|
||||
var $btn = $( this );
|
||||
|
||||
if ( $btn.hasClass( 'disabled' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.href = $btn.attr( 'data-url' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Display spinner.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*
|
||||
* @param {jQuery} $el Section number image jQuery object.
|
||||
*/
|
||||
showSpinner: function( $el ) {
|
||||
|
||||
$el.siblings( '.loader' ).removeClass( 'hidden' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide spinner.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*
|
||||
* @param {jQuery} $el Section number image jQuery object.
|
||||
*/
|
||||
hideSpinner: function( $el ) {
|
||||
|
||||
$el.siblings( '.loader' ).addClass( 'hidden' );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPFormsPagesAnalytics.init();
|
||||
@@ -0,0 +1 @@
|
||||
"use strict";var WPFormsPagesAnalytics=window.WPFormsPagesAnalytics||function(e,l){var i={},o={init:function(){l(o.ready)},ready:function(){o.initVars(),o.events()},initVars:function(){i={$stepInstall:l("section.step-install"),$stepInstallNum:l("section.step-install .num img"),$stepSetup:l("section.step-setup"),$stepSetupNum:l("section.step-setup .num img"),$stepAddon:l("section.step-addon"),$stepAddonNum:l("section.step-addon .num img")}},events:function(){i.$stepInstall.on("click","button",o.stepInstallClick),i.$stepSetup.on("click","button",o.gotoURL),i.$stepAddon.on("click","button",o.gotoURL)},stepInstallClick:function(){var n=l(this),s=n.attr("data-action"),t=n.attr("data-plugin"),a="";if(!n.hasClass("disabled")){switch(s){case"activate":a="wpforms_activate_addon",n.text(wpforms_pluginlanding.activating);break;case"install":a="wpforms_install_addon",n.text(wpforms_pluginlanding.installing);break;case"goto-url":return void(e.location.href=n.attr("data-url"));default:return}n.addClass("disabled"),o.showSpinner(i.$stepInstallNum);t={action:a,nonce:wpforms_admin.nonce,plugin:t,type:"plugin"};l.post(wpforms_admin.ajax_url,t).done(function(t){o.stepInstallDone(t,n,s)}).always(function(){o.hideSpinner(i.$stepInstallNum)})}},stepInstallDone:function(t,n,s){var a;("install"===s?t.success&&t.data.is_activated:t.success)?(i.$stepInstallNum.attr("src",i.$stepInstallNum.attr("src").replace("step-1.","step-complete.")),n.addClass("grey").removeClass("button-primary").text(wpforms_pluginlanding.activated),o.stepInstallPluginStatus()):(s=(t="install"===s&&t.success&&!t.data.is_activated||"activate"===s)?wpforms_pluginlanding.mi_manual_activate_url:wpforms_pluginlanding.mi_manual_install_url,a=t?wpforms_pluginlanding.error_could_not_activate:wpforms_pluginlanding.error_could_not_install,t=t?wpforms_pluginlanding.plugins_page:wpforms_pluginlanding.download_now,n.removeClass("grey disabled").text(t).attr("data-action","goto-url").attr("data-url",s),n.after('<p class="error">'+a+"</p>"))},stepInstallPluginStatus:function(){var t={action:"wpforms_analytics_page_check_plugin_status",nonce:wpforms_admin.nonce};l.post(wpforms_admin.ajax_url,t).done(o.stepInstallPluginStatusDone)},stepInstallPluginStatusDone:function(t){t.success&&(i.$stepSetup.removeClass("grey"),i.$stepSetupBtn=i.$stepSetup.find("button"),0<t.data.setup_status?(i.$stepSetupNum.attr("src",i.$stepSetupNum.attr("src").replace("step-2.svg","step-complete.svg")),i.$stepAddon.removeClass("grey"),i.$stepAddon.find("button").attr("data-url",t.data.step3_button_url).removeClass("grey disabled").addClass("button-primary"),"pro"===t.data.license_level&&(t=0<t.data.addon_installed?wpforms_pluginlanding.activate_now:wpforms_pluginlanding.install_now,i.$stepAddon.find("button").text(t))):i.$stepSetupBtn.removeClass("grey disabled").addClass("button-primary"))},gotoURL:function(){var t=l(this);t.hasClass("disabled")||(e.location.href=t.attr("data-url"))},showSpinner:function(t){t.siblings(".loader").removeClass("hidden")},hideSpinner:function(t){t.siblings(".loader").addClass("hidden")}};return o}((document,window),jQuery);WPFormsPagesAnalytics.init();
|
||||
@@ -0,0 +1,259 @@
|
||||
/* global wpforms_pluginlanding, wpforms_admin */
|
||||
|
||||
/**
|
||||
* SMTP Sub-page.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var WPFormsPagesSMTP = window.WPFormsPagesSMTP || ( function( document, window, $ ) {
|
||||
|
||||
/**
|
||||
* Elements.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var el = {};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*/
|
||||
init: function() {
|
||||
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*/
|
||||
ready: function() {
|
||||
|
||||
app.initVars();
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Init variables.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*/
|
||||
initVars: function() {
|
||||
|
||||
el = {
|
||||
$stepInstall: $( 'section.step-install' ),
|
||||
$stepInstallNum: $( 'section.step-install .num img' ),
|
||||
$stepSetup: $( 'section.step-setup' ),
|
||||
$stepSetupNum: $( 'section.step-setup .num img' ),
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Register JS events.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*/
|
||||
events: function() {
|
||||
|
||||
// Step 'Install' button click.
|
||||
el.$stepInstall.on( 'click', 'button', app.stepInstallClick );
|
||||
|
||||
// Step 'Setup' button click.
|
||||
el.$stepSetup.on( 'click', 'button', app.gotoURL );
|
||||
},
|
||||
|
||||
/**
|
||||
* Step 'Install' button click.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*/
|
||||
stepInstallClick: function() {
|
||||
|
||||
const $btn = $( this );
|
||||
|
||||
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' ),
|
||||
source = $btn.attr( 'data-source' );
|
||||
|
||||
const data = {
|
||||
action: ajaxAction,
|
||||
nonce: wpforms_admin.nonce,
|
||||
plugin,
|
||||
type: 'plugin',
|
||||
source,
|
||||
};
|
||||
|
||||
$.post( wpforms_admin.ajax_url, data )
|
||||
.done( function( res ) {
|
||||
app.stepInstallDone( res, $btn, action );
|
||||
} )
|
||||
.always( function() {
|
||||
app.hideSpinner( el.$stepInstallNum );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Done part of the 'Install' step.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*
|
||||
* @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: function( res, $btn, action ) {
|
||||
|
||||
var success = 'install' === action ? res.success && res.data.is_activated : res.success;
|
||||
|
||||
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();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var activationFail = ( 'install' === action && res.success && ! res.data.is_activated ) || 'activate' === action,
|
||||
url = ! activationFail ? wpforms_pluginlanding.manual_install_url : wpforms_pluginlanding.manual_activate_url,
|
||||
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.5.7
|
||||
*/
|
||||
stepInstallPluginStatus: function() {
|
||||
|
||||
var data = {
|
||||
action: 'wpforms_smtp_page_check_plugin_status',
|
||||
nonce : wpforms_admin.nonce,
|
||||
};
|
||||
|
||||
$.post( wpforms_admin.ajax_url, data )
|
||||
.done( app.stepInstallPluginStatusDone );
|
||||
},
|
||||
|
||||
/**
|
||||
* Done part of the callback for step 'Install' completion.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*
|
||||
* @param {object} res Result of $.post() query.
|
||||
*/
|
||||
stepInstallPluginStatusDone: function( res ) {
|
||||
|
||||
if ( ! res.success ) {
|
||||
return;
|
||||
}
|
||||
|
||||
el.$stepSetup.removeClass( 'grey' );
|
||||
el.$stepSetupBtn = el.$stepSetup.find( 'button' );
|
||||
el.$stepSetupBtn.removeClass( 'grey disabled' ).addClass( 'button-primary' );
|
||||
|
||||
if ( res.data.setup_status > 0 ) {
|
||||
el.$stepSetupNum.attr( 'src', el.$stepSetupNum.attr( 'src' ).replace( 'step-2.svg', 'step-complete.svg' ) );
|
||||
el.$stepSetupBtn.attr( 'data-url', wpforms_pluginlanding.smtp_settings_url ).text( wpforms_pluginlanding.smtp_settings );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
el.$stepSetupBtn.attr( 'data-url', wpforms_pluginlanding.smtp_wizard_url ).text( wpforms_pluginlanding.smtp_wizard );
|
||||
},
|
||||
|
||||
/**
|
||||
* Go to URL by click on the button.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*/
|
||||
gotoURL: function() {
|
||||
|
||||
var $btn = $( this );
|
||||
|
||||
if ( $btn.hasClass( 'disabled' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.href = $btn.attr( 'data-url' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Display spinner.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*
|
||||
* @param {jQuery} $el Section number image jQuery object.
|
||||
*/
|
||||
showSpinner: function( $el ) {
|
||||
|
||||
$el.siblings( '.loader' ).removeClass( 'hidden' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide spinner.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*
|
||||
* @param {jQuery} $el Section number image jQuery object.
|
||||
*/
|
||||
hideSpinner: function( $el ) {
|
||||
|
||||
$el.siblings( '.loader' ).addClass( 'hidden' );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPFormsPagesSMTP.init();
|
||||
@@ -0,0 +1 @@
|
||||
"use strict";var WPFormsPagesSMTP=window.WPFormsPagesSMTP||function(l,i){var r={},p={init:function(){i(p.ready)},ready:function(){p.initVars(),p.events()},initVars:function(){r={$stepInstall:i("section.step-install"),$stepInstallNum:i("section.step-install .num img"),$stepSetup:i("section.step-setup"),$stepSetupNum:i("section.step-setup .num img")}},events:function(){r.$stepInstall.on("click","button",p.stepInstallClick),r.$stepSetup.on("click","button",p.gotoURL)},stepInstallClick:function(){const s=i(this);if(!s.hasClass("disabled")){const e=s.attr("data-action");let t="";switch(e){case"activate":t="wpforms_activate_addon",s.text(wpforms_pluginlanding.activating);break;case"install":t="wpforms_install_addon",s.text(wpforms_pluginlanding.installing);break;case"goto-url":return void(l.location.href=s.attr("data-url"));default:return}s.addClass("disabled"),p.showSpinner(r.$stepInstallNum);var n=s.attr("data-plugin"),a=s.attr("data-source"),n={action:t,nonce:wpforms_admin.nonce,plugin:n,type:"plugin",source:a};i.post(wpforms_admin.ajax_url,n).done(function(t){p.stepInstallDone(t,s,e)}).always(function(){p.hideSpinner(r.$stepInstallNum)})}},stepInstallDone:function(t,s,n){var a;("install"===n?t.success&&t.data.is_activated:t.success)?(r.$stepInstallNum.attr("src",r.$stepInstallNum.attr("src").replace("step-1.","step-complete.")),s.addClass("grey").removeClass("button-primary").text(wpforms_pluginlanding.activated),p.stepInstallPluginStatus()):(n=(t="install"===n&&t.success&&!t.data.is_activated||"activate"===n)?wpforms_pluginlanding.manual_activate_url:wpforms_pluginlanding.manual_install_url,a=t?wpforms_pluginlanding.error_could_not_activate:wpforms_pluginlanding.error_could_not_install,t=t?wpforms_pluginlanding.plugins_page:wpforms_pluginlanding.download_now,s.removeClass("grey disabled").text(t).attr("data-action","goto-url").attr("data-url",n),s.after('<p class="error">'+a+"</p>"))},stepInstallPluginStatus:function(){var t={action:"wpforms_smtp_page_check_plugin_status",nonce:wpforms_admin.nonce};i.post(wpforms_admin.ajax_url,t).done(p.stepInstallPluginStatusDone)},stepInstallPluginStatusDone:function(t){t.success&&(r.$stepSetup.removeClass("grey"),r.$stepSetupBtn=r.$stepSetup.find("button"),r.$stepSetupBtn.removeClass("grey disabled").addClass("button-primary"),0<t.data.setup_status?(r.$stepSetupNum.attr("src",r.$stepSetupNum.attr("src").replace("step-2.svg","step-complete.svg")),r.$stepSetupBtn.attr("data-url",wpforms_pluginlanding.smtp_settings_url).text(wpforms_pluginlanding.smtp_settings)):r.$stepSetupBtn.attr("data-url",wpforms_pluginlanding.smtp_wizard_url).text(wpforms_pluginlanding.smtp_wizard))},gotoURL:function(){var t=i(this);t.hasClass("disabled")||(l.location.href=t.attr("data-url"))},showSpinner:function(t){t.siblings(".loader").removeClass("hidden")},hideSpinner:function(t){t.siblings(".loader").addClass("hidden")}};return p}((document,window),jQuery);WPFormsPagesSMTP.init();
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,229 @@
|
||||
/* global wpforms_admin, wpforms_admin_payments_single */
|
||||
|
||||
/**
|
||||
* WPForms Single Payment View page.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*/
|
||||
|
||||
const WPFormsPaymentsSingle = window.WPFormsPaymentsSingle || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*/
|
||||
ready() {
|
||||
app.initTooltips();
|
||||
app.paymentDeletionAlert();
|
||||
app.actionButtons();
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize WPForms admin area tooltips.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*/
|
||||
initTooltips() {
|
||||
if ( typeof jQuery.fn.tooltipster === 'undefined' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
jQuery( '.wpforms-single-payment-tooltip' ).tooltipster( {
|
||||
contentCloning: true,
|
||||
theme: 'borderless',
|
||||
contentAsHTML: true,
|
||||
position: 'top',
|
||||
maxWidth: 500,
|
||||
multiple: true,
|
||||
interactive: true,
|
||||
debug: false,
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Alert user before deleting payment.
|
||||
*
|
||||
* @since 1.8.2
|
||||
*/
|
||||
paymentDeletionAlert() {
|
||||
$( document ).on( 'click', '.wpforms-payment-actions .button-delete', function( event ) {
|
||||
event.preventDefault();
|
||||
|
||||
const url = $( this ).attr( 'href' );
|
||||
|
||||
// Trigger alert modal to confirm.
|
||||
$.confirm( {
|
||||
title: wpforms_admin.heads_up,
|
||||
content: wpforms_admin_payments_single.payment_delete_confirm,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_admin.ok,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action() {
|
||||
window.location = url;
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_admin.cancel,
|
||||
keys: [ 'esc' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle payment actions.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*/
|
||||
actionButtons() {
|
||||
$( document ).on( 'click', '.wpforms-payments-single-action', ( event ) => {
|
||||
const gateway = $( event.currentTarget ).data( 'gateway' ),
|
||||
registeredHandlers = wpforms_admin.single_payment_button_handlers;
|
||||
|
||||
if ( ! registeredHandlers || ! registeredHandlers.includes( gateway ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
const paymentId = $( event.currentTarget ).data( 'action-id' ),
|
||||
actionType = $( event.currentTarget ).data( 'action-type' );
|
||||
|
||||
$.confirm( {
|
||||
title: wpforms_admin.heads_up,
|
||||
content: app.strings[ actionType ].confirm,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_admin.ok,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action: () => {
|
||||
app.sendActionRequest( paymentId, gateway, actionType );
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_admin.cancel,
|
||||
keys: [ 'esc' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Send action request to server.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*
|
||||
* @param {number} paymentId Payment ID.
|
||||
* @param {string} gateway Payment gateway.
|
||||
* @param {string} actionType Action type.
|
||||
*/
|
||||
sendActionRequest( paymentId, gateway, actionType ) {
|
||||
$.ajax( {
|
||||
url: wpforms_admin.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'wpforms_' + gateway + '_payments_' + actionType,
|
||||
payment_id: paymentId, // eslint-disable-line camelcase
|
||||
nonce: wpforms_admin.nonce,
|
||||
},
|
||||
dataType: 'json',
|
||||
success: ( response ) => {
|
||||
if ( response.success ) {
|
||||
$.alert( {
|
||||
title: wpforms_admin.success,
|
||||
content: app.strings[ actionType ].success,
|
||||
icon: 'fa fa-check-circle',
|
||||
type: 'green',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_admin.close_refresh,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action: () => {
|
||||
window.location.reload();
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
} else {
|
||||
app.failedResponseAlert( response?.data?.modal_msg || '' );
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
app.failedResponseAlert();
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Strings.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*/
|
||||
strings : {
|
||||
refund: {
|
||||
confirm: wpforms_admin_payments_single.payment_refund_confirm,
|
||||
success: wpforms_admin_payments_single.payment_refund_success,
|
||||
},
|
||||
cancel: {
|
||||
confirm: wpforms_admin_payments_single.payment_cancel_confirm,
|
||||
success: wpforms_admin_payments_single.payment_cancel_success,
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Alert user when refunding payment failed.
|
||||
*
|
||||
* @since 1.8.4
|
||||
*
|
||||
* @param {string} message Modal message.
|
||||
*/
|
||||
failedResponseAlert( message = '' ) {
|
||||
$.alert( {
|
||||
title: wpforms_admin.heads_up,
|
||||
content: message === '' ? wpforms_admin.try_again : message,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'red',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_admin.ok,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
};
|
||||
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPFormsPaymentsSingle.init();
|
||||
@@ -0,0 +1 @@
|
||||
const WPFormsPaymentsSingle=window.WPFormsPaymentsSingle||function(n,s,a){const i={init(){a(i.ready)},ready(){i.initTooltips(),i.paymentDeletionAlert(),i.actionButtons()},initTooltips(){void 0!==jQuery.fn.tooltipster&&jQuery(".wpforms-single-payment-tooltip").tooltipster({contentCloning:!0,theme:"borderless",contentAsHTML:!0,position:"top",maxWidth:500,multiple:!0,interactive:!0,debug:!1})},paymentDeletionAlert(){a(n).on("click",".wpforms-payment-actions .button-delete",function(n){n.preventDefault();const e=a(this).attr("href");a.confirm({title:wpforms_admin.heads_up,content:wpforms_admin_payments_single.payment_delete_confirm,icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_admin.ok,btnClass:"btn-confirm",keys:["enter"],action(){s.location=e}},cancel:{text:wpforms_admin.cancel,keys:["esc"]}}})})},actionButtons(){a(n).on("click",".wpforms-payments-single-action",n=>{const e=a(n.currentTarget).data("gateway"),t=wpforms_admin.single_payment_button_handlers;if(t&&t.includes(e)){n.preventDefault();const s=a(n.currentTarget).data("action-id"),o=a(n.currentTarget).data("action-type");a.confirm({title:wpforms_admin.heads_up,content:i.strings[o].confirm,icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_admin.ok,btnClass:"btn-confirm",keys:["enter"],action:()=>{i.sendActionRequest(s,e,o)}},cancel:{text:wpforms_admin.cancel,keys:["esc"]}}})}})},sendActionRequest(n,e,t){a.ajax({url:wpforms_admin.ajax_url,type:"POST",data:{action:"wpforms_"+e+"_payments_"+t,payment_id:n,nonce:wpforms_admin.nonce},dataType:"json",success:n=>{n.success?a.alert({title:wpforms_admin.success,content:i.strings[t].success,icon:"fa fa-check-circle",type:"green",buttons:{confirm:{text:wpforms_admin.close_refresh,btnClass:"btn-confirm",keys:["enter"],action:()=>{s.location.reload()}}}}):i.failedResponseAlert(n?.data?.modal_msg||"")},error:()=>{i.failedResponseAlert()}})},strings:{refund:{confirm:wpforms_admin_payments_single.payment_refund_confirm,success:wpforms_admin_payments_single.payment_refund_success},cancel:{confirm:wpforms_admin_payments_single.payment_cancel_confirm,success:wpforms_admin_payments_single.payment_cancel_success}},failedResponseAlert(n=""){a.alert({title:wpforms_admin.heads_up,content:""===n?wpforms_admin.try_again:n,icon:"fa fa-exclamation-circle",type:"red",buttons:{confirm:{text:wpforms_admin.ok,btnClass:"btn-confirm",keys:["enter"]}}})}};return i}(document,window,jQuery);WPFormsPaymentsSingle.init();
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,230 @@
|
||||
/* global define */
|
||||
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* This file contains a reusable, and dependency-free JavaScript class,
|
||||
* providing a contrast checker. This class allows you to assess the readability
|
||||
* of the given background and text colors against the WCAG 2.0 AA standard.
|
||||
*
|
||||
* Example Usage:
|
||||
*
|
||||
* // Create an instance of the plugin with custom settings.
|
||||
* const contrastChecker = new WPFormsColorContrastChecker({
|
||||
* textColor: '#de8e8e', // Replace with your actual text color.
|
||||
* bgColor: '#ffffff', // Replace with your actual background color.
|
||||
* message: {
|
||||
* contrastPass: '',
|
||||
* contrastFail: 'Insufficient contrast. Please choose a darker text color or a lighter background color.',
|
||||
* },
|
||||
* });
|
||||
*
|
||||
* // Perform the contrast check.
|
||||
* const contrastFailed = contrastChecker.checkContrast();
|
||||
*
|
||||
* // Display the result or handle the error, if any.
|
||||
* if (contrastFailed) {
|
||||
* console.error(contrastFailed);
|
||||
* }
|
||||
*/
|
||||
/* eslint-enable */
|
||||
|
||||
( function( root, factory ) {
|
||||
const pluginName = 'WPFormsColorContrastChecker';
|
||||
|
||||
if ( typeof define === 'function' && define.amd ) {
|
||||
define( [], factory( pluginName ) );
|
||||
} else if ( typeof exports === 'object' ) {
|
||||
module.exports = factory( pluginName );
|
||||
} else {
|
||||
root[ pluginName ] = factory( pluginName );
|
||||
}
|
||||
// eslint-disable-next-line max-lines-per-function
|
||||
}( this, function( pluginName ) {
|
||||
// eslint-disable-next-line strict
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Plugin Error Object.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @class PluginError
|
||||
*
|
||||
* @augments Error
|
||||
*/
|
||||
class PluginError extends Error {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} message The error message.
|
||||
*/
|
||||
constructor( message ) {
|
||||
super( message );
|
||||
|
||||
this.name = pluginName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the error message.
|
||||
* This function can be replaced with a custom error logging logic.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} error The error message.
|
||||
*/
|
||||
function logError( error ) {
|
||||
// Custom error logging logic.
|
||||
// Display the error message in a specific format or send it to a logging service
|
||||
// eslint-disable-next-line no-console
|
||||
console.error( error );
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin Object.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @class Plugin
|
||||
*/
|
||||
class Plugin {
|
||||
// Default settings.
|
||||
static defaults = {
|
||||
textColor: '',
|
||||
bgColor: '',
|
||||
contrastThreshold: 4.5, // W3C recommended minimum contrast ratio for normal text
|
||||
message: {
|
||||
contrastPass: 'The contrast ratio between the text and background color is sufficient.',
|
||||
contrastFail: 'The contrast ratio between the text and background color is insufficient. Please choose a darker text color or a lighter background color.',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} args The argument object.
|
||||
*/
|
||||
constructor( args ) {
|
||||
// Merge the default settings with the provided settings.
|
||||
this.args = Object.assign( {}, Plugin.defaults, args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert hex color code to an RGB array.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} hexColor The hex color code.
|
||||
*
|
||||
* @return {number[]|null} The RGB array or null if the conversion failed.
|
||||
*/
|
||||
hexToRgb( hexColor ) {
|
||||
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec( hexColor );
|
||||
|
||||
if ( shorthandRegex.test( hexColor ) ) {
|
||||
return result ? [
|
||||
parseInt( result[ 1 ], 16 ) * 17,
|
||||
parseInt( result[ 2 ], 16 ) * 17,
|
||||
parseInt( result[ 3 ], 16 ) * 17,
|
||||
] : null;
|
||||
}
|
||||
|
||||
return result ? [
|
||||
parseInt( result[ 1 ], 16 ),
|
||||
parseInt( result[ 2 ], 16 ),
|
||||
parseInt( result[ 3 ], 16 ),
|
||||
] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate relative luminance for a color.
|
||||
*
|
||||
* The calculated relative luminance is a value between 0 and 1,
|
||||
* where 0 represents black and 1 represents white.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} rgb The RGB color code.
|
||||
*
|
||||
* @return {number} The relative luminance.
|
||||
*/
|
||||
calculateRelativeLuminance( rgb ) {
|
||||
for ( let i = 0; i < rgb.length; i++ ) {
|
||||
rgb[ i ] /= 255;
|
||||
rgb[ i ] = rgb[ i ] <= 0.03928 ? rgb[ i ] / 12.92 : Math.pow( ( rgb[ i ] + 0.055 ) / 1.055, 2.4 );
|
||||
}
|
||||
|
||||
// As Stated in WCAG the relative luminance of a color is defined as:
|
||||
// L = 0.2126 * R + 0.7152 * G + 0.0722 * B
|
||||
// where R, G and B are the color values normalized to the range [0, 1].
|
||||
// @see https://www.w3.org/WAI/GL/wiki/Relative_luminance
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
return 0.2126 * rgb[ 0 ] + 0.7152 * rgb[ 1 ] + 0.0722 * rgb[ 2 ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contrast ratio between two colors.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @return {number|null} The contrast ratio or an error if the calculation failed.
|
||||
*/
|
||||
getContrastRatio() {
|
||||
try {
|
||||
const rgbText = this.hexToRgb( this.args.textColor );
|
||||
const rgbBg = this.hexToRgb( this.args.bgColor );
|
||||
|
||||
// Check for invalid color format
|
||||
if ( ! rgbText || ! rgbBg ) {
|
||||
throw new PluginError( 'Invalid color format. Provide valid hex color codes.' );
|
||||
}
|
||||
|
||||
const [ l1, l2 ] = [ this.calculateRelativeLuminance( rgbText ), this.calculateRelativeLuminance( rgbBg ) ];
|
||||
|
||||
// The purpose of adding 0.05 to both the maximum and minimum relative luminance
|
||||
// is to ensure that even if one of the luminance values is zero (which would cause division by zero),
|
||||
// the result won't be infinite. This kind of adjustment is common in contrast ratio calculations
|
||||
// to handle extreme cases and avoid mathematical errors.
|
||||
return ( Math.max( l1, l2 ) + 0.05 ) / ( Math.min( l1, l2 ) + 0.05 );
|
||||
} catch ( error ) {
|
||||
logError( error.message );
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the contrast and provide a warning if it's below the threshold.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @return {string|null} The contrast check result or boolean false if the check failed.
|
||||
*/
|
||||
checkContrast() {
|
||||
try {
|
||||
const contrastRatio = this.getContrastRatio();
|
||||
|
||||
// Return early if invalid color format
|
||||
if ( contrastRatio === null ) {
|
||||
throw new PluginError( 'Invalid contrast ratio. Provide valid contrast ratio between two colors.' );
|
||||
}
|
||||
|
||||
// Warn if the contrast is below the threshold.
|
||||
if ( contrastRatio < this.args.contrastThreshold ) {
|
||||
return this.args.message.contrastFail;
|
||||
}
|
||||
|
||||
return this.args.message.contrastPass;
|
||||
} catch ( error ) {
|
||||
logError( error.message );
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Plugin;
|
||||
} ) );
|
||||
@@ -0,0 +1 @@
|
||||
!function(t,e){var r="WPFormsColorContrastChecker";"function"==typeof define&&define.amd?define([],e(r)):"object"==typeof exports?module.exports=e(r):t[r]=e(r)}(this,function(e){"use strict";class o extends Error{constructor(t){super(t),this.name=e}}function s(t){console.error(t)}return class r{static defaults={textColor:"",bgColor:"",contrastThreshold:4.5,message:{contrastPass:"The contrast ratio between the text and background color is sufficient.",contrastFail:"The contrast ratio between the text and background color is insufficient. Please choose a darker text color or a lighter background color."}};constructor(t){this.args=Object.assign({},r.defaults,t)}hexToRgb(t){var e=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(t);return/^#?([a-f\d])([a-f\d])([a-f\d])$/i.test(t)?e?[17*parseInt(e[1],16),17*parseInt(e[2],16),17*parseInt(e[3],16)]:null:e?[parseInt(e[1],16),parseInt(e[2],16),parseInt(e[3],16)]:null}calculateRelativeLuminance(e){for(let t=0;t<e.length;t++)e[t]/=255,e[t]=e[t]<=.03928?e[t]/12.92:Math.pow((e[t]+.055)/1.055,2.4);return.2126*e[0]+.7152*e[1]+.0722*e[2]}getContrastRatio(){try{var t,e,r=this.hexToRgb(this.args.textColor),a=this.hexToRgb(this.args.bgColor);if(r&&a)return[t,e]=[this.calculateRelativeLuminance(r),this.calculateRelativeLuminance(a)],(Math.max(t,e)+.05)/(Math.min(t,e)+.05);throw new o("Invalid color format. Provide valid hex color codes.")}catch(t){return s(t.message),null}}checkContrast(){try{var t=this.getContrastRatio();if(null===t)throw new o("Invalid contrast ratio. Provide valid contrast ratio between two colors.");return t<this.args.contrastThreshold?this.args.message.contrastFail:this.args.message.contrastPass}catch(t){return s(t.message),null}}}});
|
||||
@@ -0,0 +1,847 @@
|
||||
/* global wpforms_admin, htmx */
|
||||
|
||||
/**
|
||||
* WPForms admin. Extend list tables functionality.
|
||||
*
|
||||
* @param wpforms_admin.column_selector_title
|
||||
* @param wpforms_admin.save_changes
|
||||
* @param wpforms_admin.uh_oh
|
||||
* @param wpforms_admin.unknown_error
|
||||
* @param wpforms_admin.column_selector_no_fields
|
||||
* @param wpforms_admin.column_selector_no_meta
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
var WPFormsAdminListTableExt = window.WPFormsAdminListTableExt || ( function( document, window, $ ) { // eslint-disable-line no-var
|
||||
/**
|
||||
* Supported pages' CSS selectors.
|
||||
* It is the ids of the `.wpforms-admin-wrap` container, which reflects `page` + `view` URL attributes.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @type {Array}
|
||||
*/
|
||||
const supportedPages = [
|
||||
'#wpforms-overview',
|
||||
'#wpforms-entries-list',
|
||||
];
|
||||
|
||||
/**
|
||||
* Element selectors shared between functions.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const selectors = {
|
||||
cogIcon: '#wpforms-list-table-ext-edit-columns-cog',
|
||||
submitButton: '#wpforms-list-table-ext-edit-columns-select-submit',
|
||||
};
|
||||
|
||||
/**
|
||||
* Elements.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const el = {};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
init() {
|
||||
app.initElements();
|
||||
|
||||
el.$doc.on( 'wpformsReady', app.initMultiSelect );
|
||||
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
ready() {
|
||||
app.initPagination();
|
||||
app.prepareTableFootColumns();
|
||||
app.initTableScrollColumns();
|
||||
app.initTableSortableColumns();
|
||||
app.events();
|
||||
app.windowResize();
|
||||
},
|
||||
|
||||
/**
|
||||
* Events.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
events() {
|
||||
el.$doc
|
||||
.on( 'click', selectors.cogIcon, app.onClickCog )
|
||||
.on( 'wpforms_multiselect_checkbox_list_toggle', app.onMenuToggle )
|
||||
.on( 'click', selectors.submitButton, app.onSaveChanges )
|
||||
.on( 'click', '.tablenav-pages a.button', app.clickPaginationButton )
|
||||
.on( 'keydown', '#wpforms-overview-search-term', app.searchTermKeydown )
|
||||
.on( 'htmx:beforeSwap', app.htmxBeforeSwap )
|
||||
.on( 'htmx:afterSettle', app.htmxAfterSettle );
|
||||
|
||||
el.$tableScroll?.on( 'scroll', app.tableScroll );
|
||||
|
||||
// noinspection TypeScriptUMDGlobal
|
||||
$( window ).on( 'resize', _.debounce( app.windowResize, 100 ) );
|
||||
|
||||
el.$searchInput?.on( 'input', _.debounce( app.maybeShowNoResults, 310 ) ); // On 300 ms the multiselect lib is updating the list of items so we need to wait a bit more.
|
||||
},
|
||||
|
||||
/**
|
||||
* Init elements.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
initElements() {
|
||||
el.$doc = $( document );
|
||||
el.$body = $( 'body' );
|
||||
el.$header = $( '#wpforms-header' );
|
||||
el.$page = $( supportedPages.join( ',' ) );
|
||||
el.$table = el.$page.find( '.wp-list-table' );
|
||||
el.$tableContainer = el.$table.parent();
|
||||
el.$menu = $( '#wpforms-list-table-ext-edit-columns-select-container' );
|
||||
el.$cog = app.initCogIcon();
|
||||
el.$wpcontent = $( '#wpcontent' );
|
||||
el.$tablenavPages = $( '.tablenav-pages' );
|
||||
el.$tablenavPagesLinks = $( '.tablenav-pages .pagination-links a' );
|
||||
|
||||
// The Forms Overview page has no table container, wrap the table.
|
||||
if ( ! el.$tableContainer.hasClass( 'wpforms-table-container' ) ) {
|
||||
el.$table.wrap( '<div class="wpforms-table-container"></div>' );
|
||||
el.$tableContainer = el.$table.parent();
|
||||
}
|
||||
|
||||
// Add specific classes to the page container.
|
||||
el.$page.addClass( 'wpforms-list-table-ext-page' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Init pagination.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
initPagination() {
|
||||
// Prevent the error messages in console.
|
||||
htmx.config.historyCacheSize = 2;
|
||||
|
||||
const perPage = $( '#pagination_per_page, #wpforms_entries_per_page' ).val();
|
||||
|
||||
// Do not proceed if the perPage value is too high.
|
||||
// The HTMX pagination will be disabled in this case to avoid console errors coused by the large size of the page HTML.
|
||||
if ( perPage > 200 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$( '.tablenav-pages .pagination-links a' ).each( function() {
|
||||
const $link = $( this );
|
||||
const url = $link.attr( 'href' );
|
||||
|
||||
$link
|
||||
.attr( {
|
||||
'hx-get': url,
|
||||
'hx-target': '.wpforms-admin-content',
|
||||
'hx-swap': 'outerHTML',
|
||||
'hx-select': '.wpforms-admin-content',
|
||||
'hx-replace-url': 'true',
|
||||
} );
|
||||
|
||||
htmx.process( $link[ 0 ] );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Click pagination button event handler.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
clickPaginationButton() {
|
||||
el.$body.addClass( 'wpforms-loading' );
|
||||
},
|
||||
|
||||
/**
|
||||
* The search term keydown event handler.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {Event} e Event.
|
||||
*/
|
||||
searchTermKeydown( e ) {
|
||||
if ( e.keyCode === 13 ) {
|
||||
$( '#current-page-selector' ).val( 1 );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The `htmx:beforeSwap` event handler.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
htmxBeforeSwap() {
|
||||
el.$cog.detach();
|
||||
},
|
||||
|
||||
/**
|
||||
* The `htmx:afterSettle` event handler.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
htmxAfterSettle() {
|
||||
app.initElements();
|
||||
app.initMultiSelect();
|
||||
app.prepareTableFootColumns();
|
||||
app.initTableSortableColumns();
|
||||
app.initTableScrollColumns();
|
||||
|
||||
el.$tableScroll?.on( 'scroll', app.tableScroll );
|
||||
app.windowResize();
|
||||
app.initPagination();
|
||||
app.initMobileRowExpander();
|
||||
|
||||
window.WPFormsForms?.Overview.htmxAfterSettle();
|
||||
window.WPFormsPagesEntries?.htmxAfterSettle();
|
||||
|
||||
el.$body.removeClass( 'wpforms-loading' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Init mobile view row expander.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
initMobileRowExpander() {
|
||||
$( 'tbody' ).on( 'click', '.toggle-row', function() {
|
||||
$( this ).closest( 'tr' ).toggleClass( 'is-expanded' );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepare table footer columns. Their IDs should match the IDs of the header columns.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
prepareTableFootColumns() {
|
||||
el.$table.find( 'thead tr .manage-column' ).each( function() {
|
||||
const columnId = $( this ).attr( 'id' );
|
||||
|
||||
el.$table.find( 'tfoot tr .column-' + columnId ).attr( 'id', columnId + '-foot' );
|
||||
} );
|
||||
|
||||
// Disable sorting of the cog column.
|
||||
el.$table.find( '.manage-column.column-cog' )
|
||||
.addClass( 'wpforms-table-cell-sticky' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize table columns sortable container.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
initTableSortableColumns() { // eslint-disable-line max-lines-per-function
|
||||
let $columnCells,
|
||||
columnId;
|
||||
|
||||
el.$table.find( 'thead tr, tfoot tr' ).each( function() { // eslint-disable-line max-lines-per-function
|
||||
const $sortable = $( this );
|
||||
|
||||
$sortable.sortable( {
|
||||
items: '> th:not(:first-child):not(.wpforms-table-cell-sticky)',
|
||||
connectWith: '',
|
||||
delay: 100,
|
||||
opacity: 0.75,
|
||||
cursor: 'move',
|
||||
cancel: '.wpforms-table-column-not-draggable',
|
||||
placeholder: 'wpforms-table-column-drag-placeholder',
|
||||
appendTo: el.$page,
|
||||
zindex: 10000,
|
||||
tolerance: 'intersect',
|
||||
distance: 1,
|
||||
helper( e, origin ) {
|
||||
const $el = $( origin ),
|
||||
$helper = $el.clone(),
|
||||
width = $el.outerWidth();
|
||||
|
||||
return $helper.css( 'width', width + 'px' );
|
||||
},
|
||||
start( e, ui ) {
|
||||
ui.helper.addClass( 'wpforms-table-column-drag-helper' ); // Add a specific class to the helper container.
|
||||
ui.item.addClass( 'wpforms-table-column-dragged-out' ).css( 'display', '' );
|
||||
|
||||
// Disable global scrolling.
|
||||
el.$wpcontent.addClass( 'wpforms-no-scroll' );
|
||||
|
||||
columnId = ui.item.attr( 'id' ).replace( '-foot', '' );
|
||||
},
|
||||
stop( e, ui ) {
|
||||
// Remove specific classes from the helper.
|
||||
ui.item
|
||||
.removeClass( 'wpforms-table-column-drag-helper' )
|
||||
.removeClass( 'wpforms-table-column-dragged-out' );
|
||||
|
||||
// Remove previously added vertical placeholder class from all columns.
|
||||
el.$table.find( 'thead tr > *, tfoot tr > *' ).removeClass( 'wpforms-table-column-drag-placeholder-prev' );
|
||||
|
||||
// Enable global scrolling.
|
||||
el.$wpcontent.removeClass( 'wpforms-no-scroll' );
|
||||
|
||||
const prevColumnId = ui.item.prev().attr( 'id' ).replace( '-foot', '' ),
|
||||
$rows = el.$table.find( 'tbody tr:not(.wpforms-hidden)' ),
|
||||
prevSelector = prevColumnId !== 'cb' ? '.column-' + prevColumnId : '.check-column';
|
||||
|
||||
// Move column cells.
|
||||
$columnCells = $rows.find( 'td.column-' + columnId ).detach();
|
||||
|
||||
for ( let i = 0; i < $columnCells.length; i++ ) {
|
||||
$rows.eq( i ).find( prevSelector ).after( $columnCells.eq( i ) );
|
||||
}
|
||||
|
||||
// Move opposite column header.
|
||||
const oppositeColumnsSelector = ui.item.closest( 'thead' ).length > 0 ? 'tfoot' : 'thead',
|
||||
$oppositeColumn = el.$table.find( oppositeColumnsSelector + ' tr .column-' + columnId ).detach();
|
||||
|
||||
el.$table.find( oppositeColumnsSelector + ' tr ' + prevSelector ).after( $oppositeColumn );
|
||||
|
||||
app.updateMenuColumnsOrder();
|
||||
},
|
||||
change( e, ui ) {
|
||||
// Remove previously added vertical placeholder class from all columns.
|
||||
el.$table.find( 'thead tr > *, tfoot tr > *' ).removeClass( 'wpforms-table-column-drag-placeholder-prev' );
|
||||
|
||||
// Add the vertical placeholder class to the previous column.
|
||||
ui.placeholder.prev().addClass( 'wpforms-table-column-drag-placeholder-prev' );
|
||||
},
|
||||
update() {
|
||||
app.saveColumnsOrder();
|
||||
},
|
||||
} );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize table scroll sticky columns.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
initTableScrollColumns() {
|
||||
// Init table horizontal scrolling only on the Entries page.
|
||||
if ( ! el.$page.is( '#wpforms-entries-list' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
el.$tableScroll = el.$tableContainer;
|
||||
|
||||
// The Entries page has own table container, add the class.
|
||||
el.$tableScroll.addClass( 'wpforms-table-scroll' );
|
||||
|
||||
// Detect the Windows OS platform.
|
||||
el.$tableScroll.toggleClass( 'wpforms-scrollbar', app.isCustomScrollbarNeeded() );
|
||||
|
||||
// Add specific class to the sticky columns.
|
||||
el.$table.find( '.check-column, .column-indicators' )
|
||||
.addClass( 'wpforms-table-cell-sticky' )
|
||||
.addClass( 'left' );
|
||||
|
||||
el.$table.find( '.column-actions' )
|
||||
.addClass( 'wpforms-table-cell-sticky' )
|
||||
.addClass( 'right' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Table scroll event.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
tableScroll() {
|
||||
if ( ! el.$tableScroll?.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const width = el.$tableScroll.outerWidth(),
|
||||
scrollLeft = Math.abs( el.$tableScroll.get( 0 ).scrollLeft ),
|
||||
scrollWidth = el.$tableScroll.get( 0 ).scrollWidth;
|
||||
|
||||
// Conditionally Add shadow to the sticky columns.
|
||||
el.$tableScroll
|
||||
.find( '.wpforms-table-cell-sticky.left' )
|
||||
.toggleClass( 'shadow', scrollLeft > 1 ); // 1px is fix for the RTL mode.
|
||||
|
||||
el.$tableScroll
|
||||
.find( '.wpforms-table-cell-sticky.right' )
|
||||
.toggleClass( 'shadow', scrollWidth - width >= scrollLeft );
|
||||
},
|
||||
|
||||
/**
|
||||
* Window resize event.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
windowResize() {
|
||||
// Disable dragging on mobiles.
|
||||
el.$table.find( 'thead th, tfoot th' ).toggleClass( 'wpforms-table-column-not-draggable', window.innerWidth <= 782 );
|
||||
|
||||
app.closeMenu();
|
||||
app.windowResizeToggleColumns();
|
||||
app.tableScroll();
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle columns visibility for certain window sizes.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
windowResizeToggleColumns() {
|
||||
// Proceed only on the Forms Overview page.
|
||||
if ( ! el.$page.is( '#wpforms-overview' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $visibleColumns = el.$table.find( 'thead tr th:visible' );
|
||||
const $columnTags = el.$table.find( '.column-tags' );
|
||||
|
||||
// For browser window with the width between 960px and 1280px.
|
||||
if ( window.innerWidth > 960 && window.innerWidth <= 1280 ) {
|
||||
$columnTags.toggleClass( 'wpforms-hidden', $visibleColumns.length > 4 );
|
||||
} else {
|
||||
$columnTags.removeClass( 'wpforms-hidden' );
|
||||
}
|
||||
|
||||
// Synchronize menu items visibility.
|
||||
el.$menu.find( 'label' ).removeClass( 'wpforms-hidden' );
|
||||
el.$table.find( 'thead tr th:not(:visible)' ).each( function() {
|
||||
const $column = $( this );
|
||||
|
||||
el.$menu
|
||||
.find( `input[value="${ $column.attr( 'id' ) }"]` )
|
||||
.closest( 'label' )
|
||||
.addClass( 'wpforms-hidden' );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Show or hide no results text.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
maybeShowNoResults() {
|
||||
[ 'fields', 'meta' ].forEach( ( section ) => {
|
||||
const labels = el.$menu.find( '.wpforms-multiselect-checkbox-optgroup-' + section )
|
||||
.nextUntil( '.wpforms-multiselect-checkbox-optgroup' )
|
||||
.filter( 'label' );
|
||||
|
||||
const hiddenLabels = labels.filter( function() {
|
||||
return $( this ).is( ':hidden' );
|
||||
} );
|
||||
|
||||
el.$menu.find( '.wpforms-multiselect-checkbox-no-results-' + section )
|
||||
.toggleClass( 'wpforms-hidden', labels.length !== hiddenLabels.length );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Close the columns' selector menu.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
closeMenu() {
|
||||
if ( ! el.$cog.hasClass( 'active' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
el.$cog.removeClass( 'active' );
|
||||
el.$menu.find( '.wpforms-multiselect-checkbox-list' ).removeClass( 'open' );
|
||||
|
||||
// Flush the search input.
|
||||
el.$searchInput.val( '' );
|
||||
el.$searchInput[ 0 ]?.dispatchEvent( new Event( 'input' ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get columns order.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @return {Array} Columns order.
|
||||
*/
|
||||
getColumnsOrder() {
|
||||
const $row = el.$table.find( 'thead tr' );
|
||||
const columns = [];
|
||||
|
||||
$row.find( 'th' ).each( function() {
|
||||
columns.push( $( this ).attr( 'id' ) );
|
||||
} );
|
||||
|
||||
return columns;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get menu columns order.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @return {Array} Columns order.
|
||||
*/
|
||||
getMenuColumnsOrder() {
|
||||
let columnsOrder = app.getColumnsOrder();
|
||||
const columnsChecked = [];
|
||||
const columns = [];
|
||||
|
||||
el.$menu.find( `input:checked` ).each( function() {
|
||||
columnsChecked.push( $( this ).val() );
|
||||
} );
|
||||
|
||||
// Convert DOM element IDs to column IDs.
|
||||
columnsOrder = columnsOrder.map( function( column ) {
|
||||
return app.convertColumnId( column );
|
||||
} );
|
||||
|
||||
// Add checked columns in the same order as in the table.
|
||||
for ( let i = 0; i < columnsOrder.length; i++ ) {
|
||||
const column = columnsOrder[ i ];
|
||||
|
||||
if ( columnsChecked.includes( column ) ) {
|
||||
columns.push( column );
|
||||
columnsChecked.splice( columnsChecked.indexOf( column ), 1 );
|
||||
}
|
||||
}
|
||||
|
||||
// Add the rest of the checked columns.
|
||||
return columns.concat( columnsChecked );
|
||||
},
|
||||
|
||||
/**
|
||||
* Save columns order.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
saveColumnsOrder() {
|
||||
const data = {
|
||||
nonce: wpforms_admin.nonce,
|
||||
action: el.$menu.find( '[name="action"]' ).val(),
|
||||
form_id: el.$menu.find( '[name="form_id"]' ).val(), // eslint-disable-line camelcase
|
||||
columns: app.getColumnsOrder(),
|
||||
};
|
||||
|
||||
// AJAX request to save the columns order.
|
||||
$.post( wpforms_admin.ajax_url, data )
|
||||
.done( function( response ) {
|
||||
if ( ! response.success ) {
|
||||
app.displayErrorModal( response.data || wpforms_admin.unknown_error );
|
||||
}
|
||||
} )
|
||||
.fail( function() {
|
||||
app.displayErrorModal( wpforms_admin.server_error );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Display modal window with an error message.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} content Modal content.
|
||||
*/
|
||||
displayErrorModal( content ) {
|
||||
$.alert( {
|
||||
title : wpforms_admin.uh_oh,
|
||||
content,
|
||||
icon : 'fa fa-exclamation-circle',
|
||||
type : 'red',
|
||||
buttons: {
|
||||
cancel: {
|
||||
text : wpforms_admin.close,
|
||||
btnClass: 'btn-confirm',
|
||||
keys : [ 'enter' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update menu columns order.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
updateMenuColumnsOrder() { // eslint-disable-line complexity
|
||||
let columnsOrder = app.getColumnsOrder();
|
||||
const $groups = el.$menu.find( '.wpforms-multiselect-checkbox-optgroup' );
|
||||
const $itemsCont = el.$menu.find( '.wpforms-multiselect-checkbox-items' );
|
||||
const $items = $itemsCont.find( 'label' );
|
||||
const itemsByGroup = [ 0 ];
|
||||
|
||||
// If there are no groups, add the items to the first group.
|
||||
itemsByGroup[ 0 ] = $items;
|
||||
|
||||
// If there are groups, split the items by groups.
|
||||
if ( $groups.length ) {
|
||||
$groups.each( function( i ) {
|
||||
itemsByGroup[ i ] = $( this ).nextUntil( '.wpforms-multiselect-checkbox-optgroup' );
|
||||
} );
|
||||
}
|
||||
|
||||
// Convert DOM element IDs to column IDs.
|
||||
columnsOrder = columnsOrder.map( function( column ) {
|
||||
return app.convertColumnId( column );
|
||||
} );
|
||||
|
||||
// Rebuild the menu items order.
|
||||
for ( let g = 0; g < itemsByGroup.length; g++ ) {
|
||||
itemsByGroup[ g ] = itemsByGroup[ g ].filter( function() {
|
||||
return $( this ).find( 'input:checked' ).length > 0;
|
||||
} );
|
||||
|
||||
itemsByGroup[ g ].detach();
|
||||
|
||||
const $group = $groups.eq( g );
|
||||
|
||||
// Add the items in the same order as in the table.
|
||||
// It is necessary to process it in reverse mode to reproduce the columns order.
|
||||
for ( let i = columnsOrder.length - 1; i >= 0; i-- ) {
|
||||
const column = columnsOrder[ i ];
|
||||
const $item = itemsByGroup[ g ].filter( function() {
|
||||
return $( this ).find( `[value="${ column }"]` ).length > 0;
|
||||
} );
|
||||
|
||||
if ( ! $item.length ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $group.length ) {
|
||||
$group.after( $item );
|
||||
} else {
|
||||
$itemsCont.prepend( $item );
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert column Id.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string|number} columnId Column ID.
|
||||
*
|
||||
* @return {string} Converted column ID.
|
||||
*/
|
||||
convertColumnId( columnId ) {
|
||||
let id = columnId.replace( 'wpforms_field_', '' );
|
||||
|
||||
id = id.replace( '-foot', '' );
|
||||
id = id === 'entry_id' ? '-1' : id;
|
||||
id = id === 'notes_count' ? '-2' : id;
|
||||
|
||||
return id;
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize wpforms-multiselect-js on select elements.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
initMultiSelect() {
|
||||
if ( ! el.$cog.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
el.$menu.find( '.wpforms-list-table-ext-edit-columns-select' ).each( function() {
|
||||
const $select = $( this );
|
||||
const isLongList = $select.find( 'option' ).length > 10;
|
||||
const isEntriesPage = el.$page.is( '#wpforms-entries-list' );
|
||||
const showSearch = isEntriesPage && isLongList;
|
||||
const $selectWrapper = $select.parent( '.wpforms-multiselect-checkbox-dropdown' );
|
||||
|
||||
// If the multiselect is already initialized, skip.
|
||||
if ( $selectWrapper.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const multiSelectColumns = new window.WPFormsMultiSelectCheckbox(
|
||||
this,
|
||||
{
|
||||
showMask: true,
|
||||
showSearch,
|
||||
customOpener: el.$cog.get( 0 ),
|
||||
}
|
||||
);
|
||||
|
||||
// Initialize the multiselect.
|
||||
multiSelectColumns.init();
|
||||
|
||||
const $wrapper = $select.next( '.wpforms-multiselect-checkbox-wrapper' );
|
||||
const $list = $wrapper.find( '.wpforms-multiselect-checkbox-list' );
|
||||
|
||||
app.appendNoResultsText( $list );
|
||||
|
||||
if ( ! showSearch ) {
|
||||
$wrapper.find( '.wpforms-multiselect-checkbox-items' ).addClass( 'wpforms-multiselect-checkbox-items-no-search' );
|
||||
}
|
||||
|
||||
$list.append( '<button type="button" class="button button-secondary" id="wpforms-list-table-ext-edit-columns-select-submit" data-value="save-table-columns">' + wpforms_admin.save_changes + '</button>' );
|
||||
|
||||
app.updateMenuColumnsOrder();
|
||||
} );
|
||||
|
||||
el.$searchInput = $( '#wpforms-list-table-ext-edit-columns-select-container .wpforms-multiselect-checkbox-search' );
|
||||
|
||||
el.$menu.removeClass( 'wpforms-hidden' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Append no results text to the multiselect list.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {jQuery} $list Multiselect list.
|
||||
*/
|
||||
appendNoResultsText( $list ) {
|
||||
$list.find( '.wpforms-multiselect-checkbox-optgroup' ).each( function( i ) {
|
||||
const appendix = i === 0 ? 'fields' : 'meta';
|
||||
const noResultsText = i === 0 ? wpforms_admin.column_selector_no_fields : wpforms_admin.column_selector_no_meta;
|
||||
|
||||
$( this )
|
||||
.addClass( 'wpforms-multiselect-checkbox-optgroup-' + appendix )
|
||||
.after( `<span class="wpforms-multiselect-checkbox-no-results wpforms-multiselect-checkbox-no-results-${ appendix } wpforms-hidden">${ noResultsText }</span>` );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Add cog icon to the table header.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @return {jQuery} Cog icon object.
|
||||
*/
|
||||
initCogIcon() {
|
||||
const $lastColumnHeader = el.$table.find( 'thead th:not(.hidden):last' );
|
||||
|
||||
if ( ! $lastColumnHeader.length ) {
|
||||
return $();
|
||||
}
|
||||
|
||||
if ( el.$cog ) {
|
||||
$lastColumnHeader.append( el.$cog );
|
||||
return el.$cog;
|
||||
}
|
||||
|
||||
const cogId = selectors.cogIcon.replace( '#', '' );
|
||||
const $cog = $( `<a href="#" title="${ wpforms_admin.column_selector_title }" id="${ cogId }"><i class="fa fa-cog" aria-hidden="true"></i></a>` );
|
||||
|
||||
$lastColumnHeader.append( $cog );
|
||||
|
||||
return $cog;
|
||||
},
|
||||
|
||||
/*
|
||||
* Click on the cog icon.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {object} event Event object.
|
||||
*/
|
||||
onClickCog( event ) {
|
||||
event.preventDefault();
|
||||
},
|
||||
|
||||
/*
|
||||
* Save changes.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {object} event Event object.
|
||||
*/
|
||||
onSaveChanges( event ) {
|
||||
event.preventDefault();
|
||||
|
||||
const data = {
|
||||
nonce: wpforms_admin.nonce,
|
||||
action: el.$menu.find( 'input[name="action"]' ).val(),
|
||||
form_id: el.$menu.find( 'input[name="form_id"]' ).val(), // eslint-disable-line camelcase
|
||||
columns: app.getMenuColumnsOrder(),
|
||||
};
|
||||
|
||||
app.closeMenu();
|
||||
|
||||
$.post( wpforms_admin.ajax_url, data )
|
||||
.done( function( response ) {
|
||||
if ( ! response.success ) {
|
||||
app.displayErrorModal( response.data || wpforms_admin.unknown_error );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.reload();
|
||||
} )
|
||||
.fail( function() {
|
||||
app.displayErrorModal( wpforms_admin.server_error );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle multiselect columns menu.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} event Event object.
|
||||
*/
|
||||
onMenuToggle( event ) {
|
||||
$( selectors.cogIcon ).toggleClass( 'active', event.detail.isOpen );
|
||||
|
||||
// Hide no results messages.
|
||||
el.$menu.find( '.wpforms-multiselect-checkbox-no-results' ).addClass( 'wpforms-hidden' );
|
||||
|
||||
app.positionMultiselectColumnsMenu();
|
||||
},
|
||||
|
||||
/**
|
||||
* Position the multiselect columns menu just under the cog icon.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*/
|
||||
positionMultiselectColumnsMenu() {
|
||||
if ( ! el.$cog.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
el.$menu.css( {
|
||||
top: el.$cog.offset().top - $( '#wpbody-content' ).offset().top + el.$cog.outerHeight() + 6,
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Detect if the custom styled scrollbar is needed.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @return {boolean} True when needed.
|
||||
*/
|
||||
isCustomScrollbarNeeded() {
|
||||
const ua = navigator.userAgent;
|
||||
|
||||
return ( ua.includes( 'Windows' ) || ua.includes( 'Linux' ) ) &&
|
||||
( ua.includes( 'Chrome' ) || ua.includes( 'Firefox' ) );
|
||||
},
|
||||
};
|
||||
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPFormsAdminListTableExt.init();
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,196 @@
|
||||
/* global define */
|
||||
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* XOR, or exclusive or, is a logical bitwise operation that stands for "exclusive or."
|
||||
* In the context of binary numbers, XOR compares corresponding bits of two operands and
|
||||
* produces a new result. The XOR operation returns true (or 1) for bits where the operands differ.
|
||||
*
|
||||
* Note: This class is a simple obfuscation technique and should not be used for securing sensitive data.
|
||||
*
|
||||
* Here's the truth table for XOR:
|
||||
*
|
||||
* A | B | A XOR B
|
||||
* -----------------
|
||||
* 0 | 0 | 0
|
||||
* 0 | 1 | 1
|
||||
* 1 | 0 | 1
|
||||
* 1 | 1 | 0
|
||||
*
|
||||
* In binary, XOR is often denoted by the symbol ^.
|
||||
* Here's an example of XOR operation on binary numbers:
|
||||
*
|
||||
* 1101 (13 in decimal)
|
||||
* ^ 1010 (10 in decimal)
|
||||
* ------------------------
|
||||
* 0111 (7 in decimal)
|
||||
*
|
||||
* Example Usage:
|
||||
*
|
||||
* // Instantiate the plugin with a custom encryption key.
|
||||
* const xorInstance = new WPFormsXOR({
|
||||
* key: 55, // Use any number as the encryption key.
|
||||
* });
|
||||
*
|
||||
* // Example object to encrypt.
|
||||
* const dataToEncrypt = {
|
||||
* age: 30,
|
||||
* name: 'Sullie',
|
||||
* city: 'Texas',
|
||||
* };
|
||||
*
|
||||
* // Encrypt the object.
|
||||
* const encryptedValue = xorInstance.encrypt(dataToEncrypt);
|
||||
* console.log('Encrypted:', encryptedValue);
|
||||
*
|
||||
* // Decrypt the string.
|
||||
* const decryptedObject = xorInstance.decrypt(encryptedValue);
|
||||
* console.log('Decrypted:', decryptedObject);
|
||||
*/
|
||||
/* eslint-enable */
|
||||
|
||||
( function( root, factory ) {
|
||||
const pluginName = 'WPFormsXOR';
|
||||
|
||||
if ( typeof define === 'function' && define.amd ) {
|
||||
define( [], factory( pluginName ) );
|
||||
} else if ( typeof exports === 'object' ) {
|
||||
module.exports = factory( pluginName );
|
||||
} else {
|
||||
root[ pluginName ] = factory( pluginName );
|
||||
}
|
||||
// eslint-disable-next-line max-lines-per-function
|
||||
}( this, function( pluginName ) {
|
||||
// eslint-disable-next-line strict
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Plugin Error Object.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @class PluginError
|
||||
*
|
||||
* @augments Error
|
||||
*/
|
||||
class PluginError extends Error {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} message The error message.
|
||||
*/
|
||||
constructor( message ) {
|
||||
super( message );
|
||||
|
||||
this.name = pluginName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin Object.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @class Plugin
|
||||
*/
|
||||
class Plugin {
|
||||
// Default settings.
|
||||
static defaults = {
|
||||
// The encryption key is a crucial component in encryption algorithms,
|
||||
// including the XOR encryption used in the provided code.
|
||||
// The key is a value used to control the transformation
|
||||
// of the data during encryption and decryption.
|
||||
key: 42, // You can use any number.
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} args The argument object.
|
||||
*/
|
||||
constructor( args ) {
|
||||
// Merge the default settings with the provided settings.
|
||||
this.args = Object.assign( {}, Plugin.defaults, args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt an object using XOR encryption.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {Object} obj The object to encrypt.
|
||||
*
|
||||
* @return {string} The encrypted object as a string.
|
||||
*/
|
||||
encrypt( obj ) {
|
||||
// Bail if the input is not an object.
|
||||
if ( typeof obj !== 'object' ) {
|
||||
throw new PluginError( 'Invalid input. Expected an object for encryption.' );
|
||||
}
|
||||
|
||||
// Initialize an empty string to store the encrypted result.
|
||||
let result = '';
|
||||
|
||||
try {
|
||||
// Convert the object to a JSON string.
|
||||
const jsonString = JSON.stringify( obj );
|
||||
|
||||
// Iterate through each character of the JSON string.
|
||||
for ( let i = 0; i < jsonString.length; i++ ) {
|
||||
// XOR each character with the encryption key and append to the result.
|
||||
// eslint-disable-next-line no-bitwise
|
||||
result += String.fromCharCode( jsonString.charCodeAt( i ) ^ this.args.key );
|
||||
}
|
||||
} catch ( error ) {
|
||||
// Throw a PluginError if there's an issue during JSON stringification.
|
||||
throw new PluginError( 'Error during encryption. Unable to stringify the object.' );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt a string using XOR encryption.
|
||||
*
|
||||
* @since 1.8.6
|
||||
*
|
||||
* @param {string} encryptedString The encrypted string.
|
||||
*
|
||||
* @return {Object} The decrypted object.
|
||||
*/
|
||||
decrypt( encryptedString = '' ) {
|
||||
// Bail if the input is not a string.
|
||||
if ( typeof encryptedString !== 'string' ) {
|
||||
throw new PluginError( 'Invalid input. Expected a string for decryption.' );
|
||||
}
|
||||
|
||||
// Bail if there is no encrypted string.
|
||||
if ( ! encryptedString ) {
|
||||
return {}; // Return an empty object.
|
||||
}
|
||||
|
||||
let result = '';
|
||||
|
||||
try {
|
||||
// Iterate through each character of the encrypted string.
|
||||
for ( let i = 0; i < encryptedString.length; i++ ) {
|
||||
// XOR each character with the decryption key and append to the result.
|
||||
// eslint-disable-next-line no-bitwise
|
||||
result += String.fromCharCode( encryptedString.charCodeAt( i ) ^ this.args.key );
|
||||
}
|
||||
|
||||
// Parse the decrypted result as JSON or return an empty object if parsing fails.
|
||||
return JSON.parse( result || '{}' );
|
||||
} catch ( error ) {
|
||||
// Throw an error if there's an issue during decryption or parsing.
|
||||
throw new PluginError( 'Error during decryption. Unable to parse decrypted data.' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Plugin;
|
||||
} ) );
|
||||
@@ -0,0 +1 @@
|
||||
!function(t,r){var e="WPFormsXOR";"function"==typeof define&&define.amd?define([],r(e)):"object"==typeof exports?module.exports=r(e):t[e]=r(e)}(this,function(r){"use strict";class n extends Error{constructor(t){super(t),this.name=r}}return class e{static defaults={key:42};constructor(t){this.args=Object.assign({},e.defaults,t)}encrypt(t){if("object"!=typeof t)throw new n("Invalid input. Expected an object for encryption.");let r="";try{var e=JSON.stringify(t);for(let t=0;t<e.length;t++)r+=String.fromCharCode(e.charCodeAt(t)^this.args.key)}catch(t){throw new n("Error during encryption. Unable to stringify the object.")}return r}decrypt(r=""){if("string"!=typeof r)throw new n("Invalid input. Expected a string for decryption.");if(!r)return{};let e="";try{for(let t=0;t<r.length;t++)e+=String.fromCharCode(r.charCodeAt(t)^this.args.key);return JSON.parse(e||"{}")}catch(t){throw new n("Error during decryption. Unable to parse decrypted data.")}}}});
|
||||
@@ -0,0 +1,127 @@
|
||||
/* global wpforms_splash_data, ajaxurl */
|
||||
/**
|
||||
* WPForms What's New.
|
||||
*
|
||||
* @since 1.8.7
|
||||
*/
|
||||
const WPSplash = window.WPSplash || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.8.7
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Initialize.
|
||||
*
|
||||
* @since 1.8.7
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.8.7
|
||||
*/
|
||||
ready() {
|
||||
app.events();
|
||||
|
||||
if ( wpforms_splash_data.triggerForceOpen ) {
|
||||
app.openModal();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Events.
|
||||
*
|
||||
* @since 1.8.7
|
||||
*/
|
||||
events() {
|
||||
$( document )
|
||||
.on( 'click', '.wpforms-splash-modal-open', function( e ) {
|
||||
e.preventDefault();
|
||||
app.openModal();
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the modal.
|
||||
*
|
||||
* @since 1.8.7
|
||||
*/
|
||||
openModal() {
|
||||
$.alert( {
|
||||
title: false,
|
||||
content: wp.template( 'wpforms-splash-modal-content' )(),
|
||||
icon: false,
|
||||
closeIcon: true,
|
||||
boxWidth: '1000px',
|
||||
theme: 'modern',
|
||||
useBootstrap: false,
|
||||
scrollToPreviousElement: false,
|
||||
buttons: false,
|
||||
backgroundDismiss: true,
|
||||
offsetTop: 50,
|
||||
offsetBottom: 50,
|
||||
animation: 'opacity',
|
||||
closeAnimation: 'opacity',
|
||||
animateFromElement: false,
|
||||
onOpenBefore() {
|
||||
const scrollbarWidth = ( window.innerWidth - document.body.clientWidth ) + 'px';
|
||||
|
||||
$( 'body' )
|
||||
.addClass( 'wpforms-splash-modal' )
|
||||
.css( '--wpforms-body-scrollbar-width', scrollbarWidth );
|
||||
|
||||
$( '.wpforms-challenge-popup-container' ).addClass( 'wpforms-invisible' );
|
||||
|
||||
setTimeout( () => {
|
||||
if ( navigator.userAgent.includes( 'Safari' ) && ! navigator.userAgent.includes( 'Chrome' ) ) {
|
||||
$( 'html, body' ).animate( { scrollTop: 0 }, 0 );
|
||||
}
|
||||
|
||||
$( '.jconfirm-box-container' )
|
||||
.css( 'padding-top', '50px' )
|
||||
.animate( { opacity: 1 }, 30 );
|
||||
}, 0 );
|
||||
},
|
||||
onOpen() {
|
||||
$( '.jconfirm' ).css( 'bottom', 0 );
|
||||
$( '.wpforms-dash-widget-welcome-block' ).remove();
|
||||
app.dismissDashboardWidgetBanner();
|
||||
},
|
||||
onDestroy() {
|
||||
$( 'body' )
|
||||
.removeClass( 'wpforms-splash-modal' )
|
||||
.css( '--wpforms-body-scrollbar-width', null );
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Dismiss the dashboard widget banner.
|
||||
*
|
||||
* @since 1.9.0
|
||||
*/
|
||||
dismissDashboardWidgetBanner() {
|
||||
const data = {
|
||||
_wpnonce: wpforms_splash_data.nonce,
|
||||
action : 'wpforms_dash_widget_save_widget_meta',
|
||||
meta: 'hide_welcome_block',
|
||||
value: 1,
|
||||
};
|
||||
|
||||
$.post( ajaxurl, data );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
WPSplash.init();
|
||||
@@ -0,0 +1 @@
|
||||
const WPSplash=window.WPSplash||function(e,s,a){const n={init(){a(n.ready)},ready(){n.events(),wpforms_splash_data.triggerForceOpen&&n.openModal()},events(){a(e).on("click",".wpforms-splash-modal-open",function(o){o.preventDefault(),n.openModal()})},openModal(){a.alert({title:!1,content:wp.template("wpforms-splash-modal-content")(),icon:!1,closeIcon:!0,boxWidth:"1000px",theme:"modern",useBootstrap:!1,scrollToPreviousElement:!1,buttons:!1,backgroundDismiss:!0,offsetTop:50,offsetBottom:50,animation:"opacity",closeAnimation:"opacity",animateFromElement:!1,onOpenBefore(){var o=s.innerWidth-e.body.clientWidth+"px";a("body").addClass("wpforms-splash-modal").css("--wpforms-body-scrollbar-width",o),a(".wpforms-challenge-popup-container").addClass("wpforms-invisible"),setTimeout(()=>{navigator.userAgent.includes("Safari")&&!navigator.userAgent.includes("Chrome")&&a("html, body").animate({scrollTop:0},0),a(".jconfirm-box-container").css("padding-top","50px").animate({opacity:1},30)},0)},onOpen(){a(".jconfirm").css("bottom",0),a(".wpforms-dash-widget-welcome-block").remove(),n.dismissDashboardWidgetBanner()},onDestroy(){a("body").removeClass("wpforms-splash-modal").css("--wpforms-body-scrollbar-width",null)}})},dismissDashboardWidgetBanner(){var o={_wpnonce:wpforms_splash_data.nonce,action:"wpforms_dash_widget_save_widget_meta",meta:"hide_welcome_block",value:1};a.post(ajaxurl,o)}};return n}(document,window,jQuery);WPSplash.init();
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
!function i(r,a,o){function s(n,t){if(!a[n]){if(!r[n]){var e="function"==typeof require&&require;if(!t&&e)return e(n,!0);if(l)return l(n,!0);throw new Error("Cannot find module '"+n+"'")}t=a[n]={exports:{}};r[n][0].call(t.exports,function(t){var e=r[n][1][t];return s(e||t)},t,t.exports,i,r,a,o)}return a[n].exports}for(var l="function"==typeof require&&require,t=0;t<o.length;t++)s(o[t]);return s}({1:[function(t,e,n){"use strict";function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function s(t,e,n){return t.replace("{count}",e).replace("{limit}",n).replace("{remaining}",n-e)}function l(t,e,n){var i=document.createElement("div");return t="object"===r(t)?"":t,e="object"===r(e)?"":e,i.classList.add("wpforms-field-limit-text"),i.id="wpforms-field-limit-text-"+t+"-"+e,i.setAttribute("aria-live","polite"),i.textContent=n,i}function u(e){return"string"==typeof e&&e.length?([/([A-Z]+),([A-Z]+)/gi,/([0-9]+),([A-Z]+)/gi,/([A-Z]+),([0-9]+)/gi].forEach(function(t){e=e.replace(t,"$1, $2")}),e.split(/\s+/).length):0}function c(t){return window.clipboardData&&window.clipboardData.getData?window.clipboardData.getData("Text"):t.clipboardData&&t.clipboardData.getData?t.clipboardData.getData("text/plain"):""}function d(t,e){var n="",i=/\s+/g,r=t.trim().match(i)||[],a=t.split(i);a.splice(e,a.length);for(var o=0;o<a.length;o++)n+=a[o]+(r[o]||"");return n.trim()}function i(t){return[].slice.call(t)}function a(){(window.WPFormsTextLimit=o).initHint("body")}var o;o={initHint:function(t){i(document.querySelectorAll(t+" .wpforms-limit-characters-enabled")).map(function(t){function e(t){n.textContent=s(window.wpforms_settings.val_limit_characters,this.value.length,i)}var n,i,r,a=parseInt(t.dataset.textLimit,10)||0,o=(t.value=t.value.slice(0,a),l(t.dataset.formId,t.dataset.fieldId,s(wpforms_settings.val_limit_characters,t.value.length,a)));n=o,i=a;t.parentNode.appendChild(o),t.addEventListener("keydown",e),t.addEventListener("keyup",e),t.addEventListener("paste",(r=a,function(t){t.preventDefault();var t=c(t),e=this.selectionStart+t.length,t=this.value.substring(0,this.selectionStart)+t+this.value.substring(this.selectionStart);this.value=t.substring(0,r),this.setSelectionRange(e,e)}))}),i(document.querySelectorAll(t+" .wpforms-limit-words-enabled")).map(function(t){function e(t){var e=u(this.value.trim());n.textContent=s(window.wpforms_settings.val_limit_words,e,i),-1<[13,32,188].indexOf(t.keyCode)&&i<=e&&t.preventDefault()}var n,i,r,a=parseInt(t.dataset.textLimit,10)||0,o=(t.value=d(t.value,a),l(t.dataset.formId,t.dataset.fieldId,s(wpforms_settings.val_limit_words,u(t.value.trim()),a)));n=o,i=a;t.parentNode.appendChild(o),t.addEventListener("keydown",e),t.addEventListener("keyup",e),t.addEventListener("paste",(r=a,function(t){t.preventDefault();var t=c(t),e=this.selectionStart+t.length,t=this.value.substring(0,this.selectionStart)+t+this.value.substring(this.selectionStart);this.value=d(t,r),this.setSelectionRange(e,e)}))})}},"loading"===document.readyState?document.addEventListener("DOMContentLoaded",a):a()},{}]},{},[1]);
|
||||
@@ -0,0 +1,320 @@
|
||||
/* global wpforms_settings */
|
||||
|
||||
( function() {
|
||||
/**
|
||||
* Predefine hint text to display.
|
||||
*
|
||||
* @since 1.5.6
|
||||
* @since 1.6.4 Added a new macros - {remaining}.
|
||||
*
|
||||
* @param {string} hintText Hint text.
|
||||
* @param {number} count Current count.
|
||||
* @param {number} limit Limit to.
|
||||
*
|
||||
* @return {string} Predefined hint text.
|
||||
*/
|
||||
function renderHint( hintText, count, limit ) {
|
||||
return hintText.replace( '{count}', count ).replace( '{limit}', limit ).replace( '{remaining}', limit - count );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create HTMLElement hint element with text.
|
||||
*
|
||||
* @since 1.5.6
|
||||
*
|
||||
* @param {number|string} formId Form id.
|
||||
* @param {number|string} fieldId Form field id.
|
||||
* @param {string} text Hint text.
|
||||
*
|
||||
* @return {Object} HTMLElement hint element with text.
|
||||
*/
|
||||
function createHint( formId, fieldId, text ) {
|
||||
const hint = document.createElement( 'div' );
|
||||
|
||||
formId = typeof formId === 'object' ? '' : formId;
|
||||
fieldId = typeof fieldId === 'object' ? '' : fieldId;
|
||||
|
||||
hint.classList.add( 'wpforms-field-limit-text' );
|
||||
hint.id = 'wpforms-field-limit-text-' + formId + '-' + fieldId;
|
||||
hint.setAttribute( 'aria-live', 'polite' );
|
||||
hint.textContent = text;
|
||||
|
||||
return hint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keyup/Keydown event higher order function for characters limit.
|
||||
*
|
||||
* @since 1.5.6
|
||||
*
|
||||
* @param {Object} hint HTMLElement hint element.
|
||||
* @param {number} limit Max allowed number of characters.
|
||||
*
|
||||
* @return {Function} Handler function.
|
||||
*/
|
||||
function checkCharacters( hint, limit ) {
|
||||
// noinspection JSUnusedLocalSymbols
|
||||
return function( e ) { // eslint-disable-line no-unused-vars
|
||||
hint.textContent = renderHint(
|
||||
window.wpforms_settings.val_limit_characters,
|
||||
this.value.length,
|
||||
limit
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Count words in the string.
|
||||
*
|
||||
* @since 1.6.2
|
||||
*
|
||||
* @param {string} string String value.
|
||||
*
|
||||
* @return {number} Words count.
|
||||
*/
|
||||
function countWords( string ) {
|
||||
if ( typeof string !== 'string' ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( ! string.length ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
[
|
||||
/([A-Z]+),([A-Z]+)/gi,
|
||||
/([0-9]+),([A-Z]+)/gi,
|
||||
/([A-Z]+),([0-9]+)/gi,
|
||||
].forEach( function( pattern ) {
|
||||
string = string.replace( pattern, '$1, $2' );
|
||||
} );
|
||||
|
||||
return string.split( /\s+/ ).length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keyup/Keydown event higher order function for words limit.
|
||||
*
|
||||
* @since 1.5.6
|
||||
*
|
||||
* @param {Object} hint HTMLElement hint element.
|
||||
* @param {number} limit Max allowed number of characters.
|
||||
*
|
||||
* @return {Function} Handler function.
|
||||
*/
|
||||
function checkWords( hint, limit ) {
|
||||
return function( e ) {
|
||||
const value = this.value.trim(),
|
||||
words = countWords( value );
|
||||
|
||||
hint.textContent = renderHint(
|
||||
window.wpforms_settings.val_limit_words,
|
||||
words,
|
||||
limit
|
||||
);
|
||||
|
||||
// We should prevent the keys: Enter, Space, Comma.
|
||||
if ( [ 13, 32, 188 ].indexOf( e.keyCode ) > -1 && words >= limit ) {
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get passed text from the clipboard.
|
||||
*
|
||||
* @since 1.5.6
|
||||
*
|
||||
* @param {ClipboardEvent} e Clipboard event.
|
||||
*
|
||||
* @return {string} Text from clipboard.
|
||||
*/
|
||||
function getPastedText( e ) {
|
||||
if ( window.clipboardData && window.clipboardData.getData ) { // IE
|
||||
return window.clipboardData.getData( 'Text' );
|
||||
} else if ( e.clipboardData && e.clipboardData.getData ) {
|
||||
return e.clipboardData.getData( 'text/plain' );
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Paste event higher order function for character limit.
|
||||
*
|
||||
* @since 1.6.7.1
|
||||
*
|
||||
* @param {number} limit Max allowed number of characters.
|
||||
*
|
||||
* @return {Function} Event handler.
|
||||
*/
|
||||
function pasteText( limit ) {
|
||||
return function( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
const pastedText = getPastedText( e ),
|
||||
newPosition = this.selectionStart + pastedText.length,
|
||||
newText = this.value.substring( 0, this.selectionStart ) + pastedText + this.value.substring( this.selectionStart );
|
||||
|
||||
this.value = newText.substring( 0, limit );
|
||||
this.setSelectionRange( newPosition, newPosition );
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit string length to a certain number of words, preserving line breaks.
|
||||
*
|
||||
* @since 1.6.8
|
||||
*
|
||||
* @param {string} text Text.
|
||||
* @param {number} limit Max allowed number of words.
|
||||
*
|
||||
* @return {string} Text with the limited number of words.
|
||||
*/
|
||||
function limitWords( text, limit ) {
|
||||
let result = '';
|
||||
|
||||
// Regular expression pattern: match any space character.
|
||||
const regEx = /\s+/g;
|
||||
|
||||
// Store separators for further join.
|
||||
const separators = text.trim().match( regEx ) || [];
|
||||
|
||||
// Split the new text by regular expression.
|
||||
const newTextArray = text.split( regEx );
|
||||
|
||||
// Limit the number of words.
|
||||
newTextArray.splice( limit, newTextArray.length );
|
||||
|
||||
// Join the words together using stored separators.
|
||||
for ( let i = 0; i < newTextArray.length; i++ ) {
|
||||
result += newTextArray[ i ] + ( separators[ i ] || '' );
|
||||
}
|
||||
|
||||
return result.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Paste event higher order function for words limit.
|
||||
*
|
||||
* @since 1.5.6
|
||||
*
|
||||
* @param {number} limit Max allowed number of words.
|
||||
*
|
||||
* @return {Function} Event handler.
|
||||
*/
|
||||
function pasteWords( limit ) {
|
||||
return function( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
const pastedText = getPastedText( e ),
|
||||
newPosition = this.selectionStart + pastedText.length,
|
||||
newText = this.value.substring( 0, this.selectionStart ) + pastedText + this.value.substring( this.selectionStart );
|
||||
|
||||
this.value = limitWords( newText, limit );
|
||||
this.setSelectionRange( newPosition, newPosition );
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Array.from polyfill.
|
||||
*
|
||||
* @since 1.5.6
|
||||
*
|
||||
* @param {Object} el Iterator.
|
||||
*
|
||||
* @return {Object} Array.
|
||||
*/
|
||||
function arrFrom( el ) {
|
||||
return [].slice.call( el );
|
||||
}
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.8.9
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
/**
|
||||
* Init text limit hint.
|
||||
*
|
||||
* @since 1.8.9
|
||||
*
|
||||
* @param {string} context Context selector.
|
||||
*/
|
||||
initHint( context ) {
|
||||
arrFrom( document.querySelectorAll( context + ' .wpforms-limit-characters-enabled' ) )
|
||||
.map(
|
||||
function( e ) { // eslint-disable-line array-callback-return
|
||||
const limit = parseInt( e.dataset.textLimit, 10 ) || 0;
|
||||
|
||||
e.value = e.value.slice( 0, limit );
|
||||
|
||||
const hint = createHint(
|
||||
e.dataset.formId,
|
||||
e.dataset.fieldId,
|
||||
renderHint(
|
||||
wpforms_settings.val_limit_characters,
|
||||
e.value.length,
|
||||
limit
|
||||
)
|
||||
);
|
||||
|
||||
const fn = checkCharacters( hint, limit );
|
||||
|
||||
e.parentNode.appendChild( hint );
|
||||
e.addEventListener( 'keydown', fn );
|
||||
e.addEventListener( 'keyup', fn );
|
||||
e.addEventListener( 'paste', pasteText( limit ) );
|
||||
}
|
||||
);
|
||||
|
||||
arrFrom( document.querySelectorAll( context + ' .wpforms-limit-words-enabled' ) )
|
||||
.map(
|
||||
function( e ) { // eslint-disable-line array-callback-return
|
||||
const limit = parseInt( e.dataset.textLimit, 10 ) || 0;
|
||||
|
||||
e.value = limitWords( e.value, limit );
|
||||
|
||||
const hint = createHint(
|
||||
e.dataset.formId,
|
||||
e.dataset.fieldId,
|
||||
renderHint(
|
||||
wpforms_settings.val_limit_words,
|
||||
countWords( e.value.trim() ),
|
||||
limit
|
||||
)
|
||||
);
|
||||
|
||||
const fn = checkWords( hint, limit );
|
||||
|
||||
e.parentNode.appendChild( hint );
|
||||
|
||||
e.addEventListener( 'keydown', fn );
|
||||
e.addEventListener( 'keyup', fn );
|
||||
e.addEventListener( 'paste', pasteWords( limit ) );
|
||||
}
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* DOMContentLoaded handler.
|
||||
*
|
||||
* @since 1.5.6
|
||||
*/
|
||||
function ready() {
|
||||
// Expose to the world.
|
||||
window.WPFormsTextLimit = app;
|
||||
|
||||
app.initHint( 'body' );
|
||||
}
|
||||
|
||||
if ( document.readyState === 'loading' ) {
|
||||
document.addEventListener( 'DOMContentLoaded', ready );
|
||||
} else {
|
||||
ready();
|
||||
}
|
||||
}() );
|
||||
@@ -0,0 +1,21 @@
|
||||
// Clear URL - remove wpforms_form_id
|
||||
( function() {
|
||||
var loc = window.location,
|
||||
query = loc.search;
|
||||
|
||||
if ( query.indexOf( 'wpforms_form_id=' ) !== -1 ) {
|
||||
query = query.replace( /([&?]wpforms_form_id=[0-9]*$|wpforms_form_id=[0-9]*&|[?&]wpforms_form_id=[0-9]*(?=#))/, '' );
|
||||
history.replaceState( {}, null, loc.origin + loc.pathname + query );
|
||||
}
|
||||
}() );
|
||||
|
||||
( function( $ ) {
|
||||
$( function() {
|
||||
if ( $( 'div.wpforms-confirmation-scroll' ).length ) {
|
||||
$( 'html,body' ).animate(
|
||||
{ scrollTop: ( $( 'div.wpforms-confirmation-scroll' ).offset().top ) - 100 },
|
||||
1000
|
||||
);
|
||||
}
|
||||
} );
|
||||
}( jQuery ) );
|
||||
@@ -0,0 +1 @@
|
||||
!function(){var o=window.location,r=o.search;-1!==r.indexOf("wpforms_form_id=")&&(r=r.replace(/([&?]wpforms_form_id=[0-9]*$|wpforms_form_id=[0-9]*&|[?&]wpforms_form_id=[0-9]*(?=#))/,""),history.replaceState({},null,o.origin+o.pathname+r))}(),function(o){o(function(){o("div.wpforms-confirmation-scroll").length&&o("html,body").animate({scrollTop:o("div.wpforms-confirmation-scroll").offset().top-100},1e3)})}(jQuery);
|
||||
@@ -0,0 +1,544 @@
|
||||
/* global wpforms_settings, WPFormsUtils */
|
||||
|
||||
/**
|
||||
* @param wpforms_settings.css_vars
|
||||
* @param wpforms_settings.formErrorMessagePrefix
|
||||
* @param wpforms_settings.indicatorStepsPattern
|
||||
* @param wpforms_settings.submitBtnDisabled
|
||||
*/
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
/**
|
||||
* Modern Frontend.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
// eslint-disable-next-line no-var
|
||||
var WPForms = window.WPForms || {};
|
||||
|
||||
WPForms.FrontendModern = WPForms.FrontendModern || ( function( document, window, $ ) {
|
||||
// noinspection JSUnusedLocalSymbols,JSUnusedGlobalSymbols
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
init() {
|
||||
// Document ready.
|
||||
$( app.ready );
|
||||
app.bindOptinMonster();
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
ready() {
|
||||
app.updateGBBlockAccentColors();
|
||||
app.initPageBreakButtons();
|
||||
app.initButtonStyle();
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Events.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
events() {
|
||||
$( document )
|
||||
.on( 'wpforms_elementor_form_fields_initialized', app.initPageBreakButtons );
|
||||
|
||||
$( 'form.wpforms-form' )
|
||||
.on( 'wpformsCombinedUploadsSizeError', app.combinedUploadsSizeError )
|
||||
.on( 'wpformsFormSubmitButtonDisable', app.formSubmitButtonDisable )
|
||||
.on( 'wpformsFormSubmitButtonRestore', app.formSubmitButtonRestore )
|
||||
.on( 'wpformsPageChange', app.pageChange );
|
||||
|
||||
$( 'form.wpforms-form .wpforms-submit' )
|
||||
.on( 'keydown click', app.disabledButtonPress );
|
||||
|
||||
// Add styling to timepicker dropdown.
|
||||
$( document )
|
||||
.on( 'focus', '.wpforms-render-modern .wpforms-timepicker', app.updateTimepickerDropdown );
|
||||
|
||||
// Reset timepicker dropdown styles.
|
||||
$( document )
|
||||
.on( 'focusout', '.wpforms-render-modern .wpforms-timepicker', app.resetTimepickerDropdown );
|
||||
},
|
||||
|
||||
/**
|
||||
* OptinMonster compatibility.
|
||||
*
|
||||
* Re-initialize after OptinMonster loads to accommodate changes that
|
||||
* have occurred to the DOM.
|
||||
*
|
||||
* @since 1.9.0
|
||||
*/
|
||||
bindOptinMonster() {
|
||||
// OM v5.
|
||||
document.addEventListener( 'om.Campaign.load', function() {
|
||||
app.ready();
|
||||
} );
|
||||
|
||||
// OM Legacy.
|
||||
$( document ).on( 'OptinMonsterOnShow', function() {
|
||||
app.ready();
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Add styling to timepicker dropdown.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
updateTimepickerDropdown() {
|
||||
const cssVars = app.getCssVars( $( this ) );
|
||||
|
||||
setTimeout(
|
||||
function() {
|
||||
const $list = $( '.ui-timepicker-wrapper .ui-timepicker-list' );
|
||||
|
||||
$list.css( 'background', cssVars[ 'field-menu-color' ] );
|
||||
$list.find( 'li' ).css( 'color', cssVars[ 'field-text-color' ] );
|
||||
$list.find( '.ui-timepicker-selected' )
|
||||
.css( 'background', cssVars[ 'button-background-color' ] )
|
||||
.css( 'color', cssVars[ 'button-text-color' ] );
|
||||
},
|
||||
0
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Reset timepicker dropdown styles.
|
||||
*
|
||||
* @since 1.8.9.5
|
||||
*/
|
||||
resetTimepickerDropdown() {
|
||||
setTimeout(
|
||||
function() {
|
||||
const $list = $( '.ui-timepicker-wrapper .ui-timepicker-list' );
|
||||
|
||||
$list.find( ':not(.ui-timepicker-selected)' ).attr( 'style', '' );
|
||||
},
|
||||
0
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Update accent colors of some fields in GB block in Modern Markup mode.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
initButtonStyle() {
|
||||
// Loop through all the GB blocks on the page.
|
||||
$( '.wpforms-block.wpforms-container-full, .elementor-widget-wpforms .wpforms-container-full' ).each( function() {
|
||||
const $form = $( this );
|
||||
const contStyle = getComputedStyle( $form.get( 0 ) );
|
||||
const btnBgColor = app.getCssVar( contStyle, '--wpforms-button-background-color-alt' );
|
||||
|
||||
if ( app.isTransparentColor( btnBgColor ) ) {
|
||||
$form.find( 'button.wpforms-submit' ).addClass( 'wpforms-opacity-hover' );
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the provided color has transparency.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*
|
||||
* @param {string} color The color to check.
|
||||
*
|
||||
* @return {boolean} Returns true if the color is transparent.
|
||||
*/
|
||||
isTransparentColor( color ) {
|
||||
const rgba = app.getColorAsRGBArray( color );
|
||||
|
||||
// The max opacity value of the color that is considered as transparent.
|
||||
const opacityThreshold = 0.33;
|
||||
const opacity = Number( rgba?.[ 3 ] );
|
||||
|
||||
// Compare the opacity value with the threshold.
|
||||
return opacity <= opacityThreshold;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update accent colors of some fields in GB block in Modern Markup mode.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
updateGBBlockAccentColors() {
|
||||
// Loop through all the GB blocks on the page.
|
||||
$( '.wpforms-block.wpforms-container-full, .elementor-widget-wpforms .wpforms-container-full' ).each( function() {
|
||||
const $form = $( this );
|
||||
|
||||
app.updateGBBlockPageIndicatorColor( $form );
|
||||
app.updateGBBlockIconChoicesColor( $form );
|
||||
app.updateGBBlockRatingColor( $form );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update accent color of Page Indicator.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @param {jQuery} $form Form container.
|
||||
*/
|
||||
updateGBBlockPageIndicatorColor( $form ) {
|
||||
const $indicator = $form.find( '.wpforms-page-indicator' ),
|
||||
$indicatorPage = $indicator.find( '.wpforms-page-indicator-page-progress, .wpforms-page-indicator-page.active .wpforms-page-indicator-page-number' ),
|
||||
$indicatorTriangle = $indicatorPage.find( '.wpforms-page-indicator-page-triangle' );
|
||||
|
||||
$indicator.data( 'indicator-color', 'var( --wpforms-page-break-color )' );
|
||||
$indicatorPage.css( 'background-color', 'var( --wpforms-page-break-color )' );
|
||||
$indicatorTriangle.css( 'border-top-color', 'var( --wpforms-page-break-color )' );
|
||||
},
|
||||
/**
|
||||
* Update accent color of Icon Choices.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @param {jQuery} $form Form container.
|
||||
*/
|
||||
updateGBBlockIconChoicesColor( $form ) {
|
||||
$form
|
||||
.find( '.wpforms-icon-choices' )
|
||||
.css( '--wpforms-icon-choices-color', 'var( --wpforms-button-background-color )' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update accent color of Rating field.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @param {jQuery} $form Form container.
|
||||
*/
|
||||
updateGBBlockRatingColor( $form ) {
|
||||
$form
|
||||
.find( '.wpforms-field-rating-item svg' )
|
||||
.css( 'color', 'var( --wpforms-page-break-color, var( --wpforms-button-background-color ) )' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Init Page Break fields.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
initPageBreakButtons() {
|
||||
$( '.wpforms-page-button' )
|
||||
.removeClass( 'wpforms-disabled' )
|
||||
.attr( 'aria-disabled', 'false' )
|
||||
.attr( 'aria-describedby', '' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for `wpformsCombinedUploadsSizeError` event.
|
||||
* Accessibility enhancements to error container and submit button.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
* @param {jQuery} $form Form object.
|
||||
* @param {jQuery} $errorCnt Error container object.
|
||||
*/
|
||||
combinedUploadsSizeError( e, $form, $errorCnt ) {
|
||||
const formId = $form.data( 'formid' ),
|
||||
errormessage = $form.attr( 'aria-errormessage' ) || '',
|
||||
errorCntId = `wpforms-${ formId }-footer-error`,
|
||||
$submitBtn = $form.find( '.wpforms-submit' );
|
||||
|
||||
$form.attr( {
|
||||
'aria-invalid': 'true',
|
||||
'aria-errormessage': `${ errormessage } ${ errorCntId }`,
|
||||
} );
|
||||
|
||||
$errorCnt.attr( {
|
||||
role: 'alert',
|
||||
id: errorCntId,
|
||||
} );
|
||||
|
||||
// Add error message prefix.
|
||||
$errorCnt.find( '> .wpforms-hidden:first-child' ).remove();
|
||||
$errorCnt.prepend( `<span class="wpforms-hidden">${ wpforms_settings.formErrorMessagePrefix }</span>` );
|
||||
|
||||
// Instead of set the `disabled` property,
|
||||
// we must use `aria-disabled` and `aria-describedby` attributes in conduction with `wpforms-disabled` class.
|
||||
$submitBtn.attr( 'aria-describedby', errorCntId );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for `wpformsCombinedUploadsSizeOk` event.
|
||||
*
|
||||
* @since 1.8.1
|
||||
* @deprecated 1.8.3
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
* @param {jQuery} $form Form object.
|
||||
* @param {jQuery} $errorCnt Error container object.
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
combinedUploadsSizeOk( e, $form, $errorCnt ) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn( 'WARNING! Function "WPForms.FrontendModern( e, $form, $errorCnt )" has been deprecated, please use the new "formSubmitButtonDisable: function( e, $form, $submitBtn )" function instead!' );
|
||||
|
||||
const $submitBtn = $form.find( '.wpforms-submit' );
|
||||
|
||||
// Revert aria-* attributes to the normal state.
|
||||
$submitBtn
|
||||
.removeClass( 'wpforms-disabled' )
|
||||
.attr( 'aria-disabled', 'false' )
|
||||
.attr( 'aria-describedby', '' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for `wpformsFormSubmitButtonDisable` event.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
* @param {jQuery} $form Form object.
|
||||
* @param {jQuery} $submitBtn Submit a button object.
|
||||
*/
|
||||
formSubmitButtonDisable( e, $form, $submitBtn ) {
|
||||
const disabledBtnDescId = $form.attr( 'id' ) + '-submit-btn-disabled';
|
||||
|
||||
$submitBtn.before( `<div class="wpforms-hidden" id="${ disabledBtnDescId }">${ wpforms_settings.submitBtnDisabled }</div>` );
|
||||
|
||||
$submitBtn
|
||||
.prop( 'disabled', false )
|
||||
.addClass( 'wpforms-disabled' )
|
||||
.attr( 'aria-disabled', 'true' )
|
||||
.attr( 'aria-describedby', disabledBtnDescId );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for `wpformsFormSubmitButtonRestore` event.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
* @param {jQuery} $form Form object.
|
||||
* @param {jQuery} $submitBtn Submit a button object.
|
||||
*/
|
||||
formSubmitButtonRestore( e, $form, $submitBtn ) {
|
||||
const disabledBtnDescId = $form.attr( 'id' ) + '-submit-btn-disabled';
|
||||
|
||||
$form.find( '#' + disabledBtnDescId ).remove();
|
||||
|
||||
$submitBtn
|
||||
.removeClass( 'wpforms-disabled' )
|
||||
.attr( 'aria-disabled', 'false' )
|
||||
.attr( 'aria-describedby', '' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Disabled button click/keydown event handler.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
*/
|
||||
disabledButtonPress( e ) {
|
||||
const $submitBtn = $( this );
|
||||
|
||||
if ( ! $submitBtn.hasClass( 'wpforms-disabled' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( e.key === 'Enter' || e.type === 'click' ) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Page change event handler.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
* @param {number} nextPage The next page number.
|
||||
* @param {jQuery} $form Current form.
|
||||
*/
|
||||
pageChange( e, nextPage, $form ) {
|
||||
const $pageIndicator = $form.find( '.wpforms-page-indicator' );
|
||||
|
||||
if ( ! wpforms_settings.indicatorStepsPattern || ! $pageIndicator.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const totalPages = $form.find( '.wpforms-page' ).length;
|
||||
let msg = wpforms_settings.indicatorStepsPattern;
|
||||
let pageTitle;
|
||||
|
||||
msg = msg.replace( '{current}', nextPage ).replace( '{total}', totalPages );
|
||||
|
||||
if ( $pageIndicator.hasClass( 'progress' ) ) {
|
||||
pageTitle = $pageIndicator.find( '.wpforms-page-indicator-page-title' ).data( `page-${ nextPage }-title` );
|
||||
} else {
|
||||
pageTitle = $pageIndicator.find( `.wpforms-page-indicator-page-${ nextPage } .wpforms-page-indicator-page-title` ).text();
|
||||
}
|
||||
|
||||
msg = pageTitle ? pageTitle + '. ' + msg : msg;
|
||||
|
||||
$pageIndicator.attr( 'aria-valuenow', nextPage );
|
||||
app.screenReaderAnnounce( msg, 'polite' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Allows the screen reader to talk directly through the use of JS.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @param {string} text The message to be vocalised
|
||||
* @param {string} priority Aria-live priority. "polite" (by default) or "assertive".
|
||||
*/
|
||||
screenReaderAnnounce( text, priority ) {
|
||||
const el = document.createElement( 'div' );
|
||||
const id = 'wpforms-screen-reader-announce-' + Date.now();
|
||||
|
||||
el.setAttribute( 'id', id );
|
||||
el.setAttribute( 'aria-live', priority || 'polite' );
|
||||
el.classList.add( 'wpforms-screen-reader-announce' );
|
||||
|
||||
const node = document.body.appendChild( el );
|
||||
|
||||
setTimeout( function() {
|
||||
node.innerHTML = text;
|
||||
}, 100 );
|
||||
|
||||
setTimeout( function() {
|
||||
document.body.removeChild( node );
|
||||
}, 1000 );
|
||||
},
|
||||
|
||||
/**
|
||||
* Add opacity to color string.
|
||||
* Supports formats: RGB, RGBA, HEX, HEXA.
|
||||
*
|
||||
* If the given color has an alpha channel, the new alpha channel will be calculated according to the given opacity.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @param {string} color Color.
|
||||
* @param {string} opacity Opacity.
|
||||
*
|
||||
* @return {string} Color in RGBA format with an added alpha channel according to given opacity.
|
||||
*/
|
||||
getColorWithOpacity( color, opacity ) {
|
||||
// Moved to ../share/utils.js
|
||||
return WPFormsUtils.cssColorsUtils.getColorWithOpacity( color, opacity );
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove opacity from the color value.
|
||||
* Supports formats: RGB, RGBA, HEX, HEXA.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @param {string} color Color.
|
||||
*
|
||||
* @return {string} Color in RGB format.
|
||||
*/
|
||||
getSolidColor( color ) {
|
||||
color = color.trim();
|
||||
|
||||
const rgbArray = app.getColorAsRGBArray( color );
|
||||
|
||||
if ( ! rgbArray ) {
|
||||
return color;
|
||||
}
|
||||
|
||||
// Combine and return the RGB color.
|
||||
return `rgb(${ rgbArray[ 0 ] },${ rgbArray[ 1 ] },${ rgbArray[ 2 ] })`;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the given color is a valid CSS color.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @param {string} color Color.
|
||||
*
|
||||
* @return {boolean} True if the given color is a valid CSS color.
|
||||
*/
|
||||
isValidColor( color ) {
|
||||
// Moved to ../share/utils.js
|
||||
return WPFormsUtils.cssColorsUtils.isValidColor( color );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get color as an array of RGB(A) values.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @param {string} color Color.
|
||||
*
|
||||
* @return {Array|boolean} Color as an array of RGBA values. False on error.
|
||||
*/
|
||||
getColorAsRGBArray( color ) {
|
||||
// Moved to ../share/utils.js
|
||||
return WPFormsUtils.cssColorsUtils.getColorAsRGBArray( color );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get CSS variable value.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @param {Object} style Computed style object.
|
||||
* @param {string} varName Style custom property name.
|
||||
*
|
||||
* @return {string|null} CSS variable value;
|
||||
*/
|
||||
getCssVar( style, varName ) {
|
||||
if ( ! style || typeof style.getPropertyValue !== 'function' ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let value = style.getPropertyValue( varName ).trim();
|
||||
|
||||
if ( varName.includes( 'color' ) ) {
|
||||
value = value.replace( /\s/g, '' );
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get all CSS variables.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @param {jQuery} $form Form OR any element inside the form.
|
||||
*
|
||||
* @return {Object} CSS variables;
|
||||
*/
|
||||
getCssVars( $form ) {
|
||||
if ( ! $form || ! $form.length ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const $cont = $form.hasClass( 'wpforms-container' ) ? $form : $form.closest( '.wpforms-container' );
|
||||
const contStyle = getComputedStyle( $cont.get( 0 ) );
|
||||
const cssVars = wpforms_settings.css_vars;
|
||||
const vars = {};
|
||||
|
||||
for ( let i = 0; i < cssVars.length; i++ ) {
|
||||
vars[ cssVars[ i ] ] = app.getCssVar( contStyle, '--wpforms-' + cssVars[ i ] );
|
||||
}
|
||||
|
||||
return vars;
|
||||
},
|
||||
};
|
||||
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPForms.FrontendModern.init();
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,170 @@
|
||||
/* global wpforms_ai_chat_element */
|
||||
|
||||
/**
|
||||
* @param wpforms_ai_chat_element.ajaxurl
|
||||
* @param wpforms_ai_chat_element.errors.network
|
||||
* @param wpforms_ai_chat_element.errors.default
|
||||
*/
|
||||
|
||||
/**
|
||||
* The WPForms AI API wrapper.
|
||||
*
|
||||
* @since 1.9.1
|
||||
*
|
||||
* @return {Function} The app cloning function.
|
||||
*/
|
||||
export default function() { // eslint-disable-line no-unused-vars, max-lines-per-function
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.9.1
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
/**
|
||||
* AI chat mode.
|
||||
*
|
||||
* @since 1.9.1
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
mode: '',
|
||||
|
||||
/**
|
||||
* AI AJAX actions.
|
||||
*
|
||||
* @since 1.9.1
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
actions: {
|
||||
rate: 'wpforms_rate_ai_response',
|
||||
choices: 'wpforms_get_ai_choices',
|
||||
forms: 'wpforms_get_ai_form',
|
||||
},
|
||||
|
||||
/**
|
||||
* AJAX request.
|
||||
*
|
||||
* @param {Object} data Data to send.
|
||||
*
|
||||
* @return {Promise} The fetch result data promise.
|
||||
*/
|
||||
// eslint-disable-next-line complexity
|
||||
async ajax( data ) {
|
||||
if ( ! data.nonce ) {
|
||||
data.nonce = wpforms_ai_chat_element.nonce;
|
||||
}
|
||||
|
||||
const options = {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: new URLSearchParams( data ).toString(),
|
||||
};
|
||||
|
||||
const response = await fetch( wpforms_ai_chat_element.ajaxurl, options )
|
||||
.catch( ( error ) => {
|
||||
if ( error.message === 'Failed to fetch' ) {
|
||||
throw new Error( wpforms_ai_chat_element.errors.network );
|
||||
} else {
|
||||
throw new Error( error.message );
|
||||
}
|
||||
} );
|
||||
|
||||
if ( ! response.ok ) {
|
||||
throw new Error( wpforms_ai_chat_element.errors.network );
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if ( ! result.success || result.data?.error ) {
|
||||
throw new Error(
|
||||
result.data?.error ?? wpforms_ai_chat_element.errors.default,
|
||||
{
|
||||
cause: result.data?.code ?? 400,
|
||||
} );
|
||||
}
|
||||
|
||||
return result.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Prompt.
|
||||
*
|
||||
* @param {string} prompt The question to ask.
|
||||
* @param {string} sessionId Session ID.
|
||||
*
|
||||
* @return {Promise} The response data in promise.
|
||||
*/
|
||||
async prompt( prompt, sessionId ) {
|
||||
const data = {
|
||||
action: app.actions[ this.mode ] ?? app.actions.choices,
|
||||
prompt,
|
||||
};
|
||||
|
||||
if ( sessionId ) {
|
||||
data.session_id = sessionId; // eslint-disable-line camelcase
|
||||
}
|
||||
|
||||
return app.ajax( data );
|
||||
},
|
||||
|
||||
/**
|
||||
* Rate.
|
||||
*
|
||||
* @param {boolean} helpful Whether the response was helpful or not.
|
||||
* @param {string} responseId Response ID.
|
||||
*
|
||||
* @return {Promise} The response data in promise.
|
||||
*/
|
||||
async rate( helpful, responseId ) {
|
||||
const data = {
|
||||
action: app.actions.rate,
|
||||
helpful,
|
||||
response_id: responseId, // eslint-disable-line camelcase
|
||||
};
|
||||
|
||||
return app.ajax( data );
|
||||
},
|
||||
|
||||
setUp() {
|
||||
app.actions = {
|
||||
...app.actions,
|
||||
...wpforms_ai_chat_element.actions,
|
||||
};
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the AI chat mode.
|
||||
*
|
||||
* @since 1.9.1
|
||||
*
|
||||
* @param {string} mode The mode to set.
|
||||
*
|
||||
* @return {Object} The app object.
|
||||
*/
|
||||
setMode( mode ) {
|
||||
this.mode = mode;
|
||||
|
||||
return this;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a clone of an app object.
|
||||
*
|
||||
* @since 1.9.1
|
||||
*
|
||||
* @param {string} mode The AI prompt mode.
|
||||
*
|
||||
* @return {Object} Cloned app object.
|
||||
*/
|
||||
return function( mode ) {
|
||||
const obj = { ...app };
|
||||
|
||||
return obj.setUp().setMode( mode );
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export default function(){const t={mode:"",actions:{rate:"wpforms_rate_ai_response",choices:"wpforms_get_ai_choices",forms:"wpforms_get_ai_form"},async ajax(e){e.nonce||(e.nonce=wpforms_ai_chat_element.nonce);e={method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams(e).toString()},e=await fetch(wpforms_ai_chat_element.ajaxurl,e).catch(e=>{throw"Failed to fetch"===e.message?new Error(wpforms_ai_chat_element.errors.network):new Error(e.message)});if(!e.ok)throw new Error(wpforms_ai_chat_element.errors.network);e=await e.json();if(!e.success||e.data?.error)throw new Error(e.data?.error??wpforms_ai_chat_element.errors.default,{cause:e.data?.code??400});return e.data},async prompt(e,r){e={action:t.actions[this.mode]??t.actions.choices,prompt:e};return r&&(e.session_id=r),t.ajax(e)},async rate(e,r){e={action:t.actions.rate,helpful:e,response_id:r};return t.ajax(e)},setUp(){return t.actions={...t.actions,...wpforms_ai_chat_element.actions},this},setMode(e){return this.mode=e,this}};return function(e){return{...t}.setUp().setMode(e)}}
|
||||
@@ -0,0 +1,314 @@
|
||||
/* global WPFormsAIChatHTMLElement, WPFormsBuilder, wpf, wpforms_builder */
|
||||
|
||||
/**
|
||||
* The WPForms AI chat element.
|
||||
*
|
||||
* Choices helpers module.
|
||||
*
|
||||
* @since 1.9.1
|
||||
*
|
||||
* @param {WPFormsAIChatHTMLElement} chat The chat element.
|
||||
*
|
||||
* @return {Object} The choices' helpers object.
|
||||
*/
|
||||
export default function( chat ) { // eslint-disable-line max-lines-per-function
|
||||
/**
|
||||
* The `choices` mode helpers object.
|
||||
*
|
||||
* @since 1.9.1
|
||||
*/
|
||||
return {
|
||||
/**
|
||||
* Get the `choices` answer based on AI response data.
|
||||
*
|
||||
* @since 1.9.1
|
||||
*
|
||||
* @param {Object} response The response data.
|
||||
*
|
||||
* @return {string} Answer HTML markup.
|
||||
*/
|
||||
getAnswer( response ) {
|
||||
if ( response.choices?.length < 1 ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const li = [];
|
||||
|
||||
for ( const i in response.choices ) {
|
||||
li.push( `
|
||||
<li class="wpforms-ai-chat-choices-item">
|
||||
${ chat.htmlSpecialChars( response.choices[ i ] ) }
|
||||
</li>
|
||||
` );
|
||||
}
|
||||
|
||||
let answerHtml = `
|
||||
<h4>${ chat.htmlSpecialChars( response.heading ?? '' ) }</h4>
|
||||
<ol>
|
||||
${ li.join( '' ) }
|
||||
</ol>
|
||||
`;
|
||||
|
||||
// Add footer to the first answer only.
|
||||
if ( ! chat.sessionId ) {
|
||||
answerHtml += `<span>${ chat.modeStrings.footer }</span>`;
|
||||
}
|
||||
|
||||
return answerHtml;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the answer pre-buttons HTML markup.
|
||||
*
|
||||
* @since 1.9.1
|
||||
*
|
||||
* @return {string} The answer pre-buttons HTML markup.
|
||||
*/
|
||||
getAnswerButtonsPre() {
|
||||
return `
|
||||
<button type="button" class="wpforms-ai-chat-choices-insert wpforms-ai-chat-answer-action wpforms-btn-sm wpforms-btn-orange" >
|
||||
<span>${ chat.modeStrings.insert }</span>
|
||||
</button>
|
||||
`;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the warning message HTML markup.
|
||||
*
|
||||
* @since 1.9.1
|
||||
*
|
||||
* @return {string} The warning message HTML markup.
|
||||
*/
|
||||
getWarningMessage() {
|
||||
// Trigger event before warning message insert.
|
||||
chat.triggerEvent( 'wpformsAIModalBeforeWarningMessageInsert', { fieldId: chat.fieldId } );
|
||||
|
||||
return `<div class="wpforms-ai-chat-divider"></div>
|
||||
<div class="wpforms-chat-item-notice">
|
||||
<div class="wpforms-chat-item-notice-content">
|
||||
<span>${ chat.modeStrings.warning }</span>
|
||||
</div>
|
||||
</div>`;
|
||||
},
|
||||
|
||||
/**
|
||||
* If the field has default choices, the welcome screen is active.
|
||||
*
|
||||
* @since 1.9.1
|
||||
*
|
||||
* @return {boolean} True if the field has default choices, false otherwise.
|
||||
*/
|
||||
isWelcomeScreen() {
|
||||
const items = document.getElementById( `wpforms-field-option-row-${ chat.fieldId }-choices` )
|
||||
.querySelectorAll( 'li input.label' );
|
||||
|
||||
if ( items.length === 1 && ! items[ 0 ].value.trim() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( items.length > 3 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const defaults = Object.values( chat.modeStrings.defaults );
|
||||
|
||||
for ( let i = 0; i < items.length; i++ ) {
|
||||
if ( ! defaults.includes( items[ i ].value ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the `choices` answer.
|
||||
*
|
||||
* @since 1.9.1
|
||||
*
|
||||
* @param {HTMLElement} element The answer element.
|
||||
*/
|
||||
addedAnswer( element ) {
|
||||
const button = element.querySelector( '.wpforms-ai-chat-choices-insert' );
|
||||
|
||||
// Listen to the button click event.
|
||||
button?.addEventListener( 'click', this.insertButtonClick.bind( this ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* Sanitize response.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*
|
||||
* @param {Object} response The response data to sanitize.
|
||||
*
|
||||
* @return {Object} The sanitized response.
|
||||
*/
|
||||
sanitizeResponse( response ) {
|
||||
if ( ! Array.isArray( response?.choices ) ) {
|
||||
return response;
|
||||
}
|
||||
|
||||
let choices = response.choices;
|
||||
|
||||
// Sanitize choices.
|
||||
choices = choices.map( ( choice ) => {
|
||||
return wpf.sanitizeHTML( choice, wpforms_builder.allowed_label_html_tags );
|
||||
} );
|
||||
|
||||
// Remove empty choices.
|
||||
response.choices = choices.filter( ( choice ) => {
|
||||
return choice.trim() !== '';
|
||||
} );
|
||||
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the response has a prohibited code.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*
|
||||
* @param {Object} response The response data.
|
||||
* @param {Array} sanitizedResponse The sanitized response data.
|
||||
*
|
||||
* @return {boolean} Whether the answer has a prohibited code.
|
||||
*/
|
||||
hasProhibitedCode( response, sanitizedResponse ) {
|
||||
// If the number of choices has changed after sanitization, it means that the answer contains prohibited code.
|
||||
return sanitizedResponse?.choices?.length !== response?.choices?.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Click on the Use Choices button.
|
||||
*
|
||||
* @since 1.9.1
|
||||
*
|
||||
* @param {Event} e The event object.
|
||||
*/
|
||||
insertButtonClick( e ) {
|
||||
const button = e.target;
|
||||
const answer = button.closest( '.wpforms-chat-item.wpforms-chat-item-choices' );
|
||||
const responseId = answer?.getAttribute( 'data-response-id' );
|
||||
const choicesList = answer?.querySelector( 'ol' );
|
||||
const items = choicesList.querySelectorAll( '.wpforms-ai-chat-choices-item' );
|
||||
const choiceItems = [];
|
||||
|
||||
// Get choices data.
|
||||
for ( const i in items ) {
|
||||
if ( ! items.hasOwnProperty( i ) || ! items[ i ].textContent ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
choiceItems.push( items[ i ].textContent.trim() );
|
||||
}
|
||||
|
||||
// Rate the response.
|
||||
chat.wpformsAiApi.rate( true, responseId );
|
||||
|
||||
// Replace field choices.
|
||||
this.replaceChoices( choiceItems );
|
||||
},
|
||||
|
||||
/**
|
||||
* Replace field choices.
|
||||
*
|
||||
* @since 1.9.1
|
||||
*
|
||||
* @param {Array} choices Choices array.
|
||||
*/
|
||||
replaceChoices( choices ) {
|
||||
const choicesOptionRow = document.getElementById( `wpforms-field-option-row-${ chat.fieldId }-choices` );
|
||||
const choicesList = choicesOptionRow.querySelector( 'ul.choices-list' );
|
||||
const choiceRow = choicesList.querySelector( 'li:first-child' ).cloneNode( true );
|
||||
|
||||
choiceRow.innerHTML = choiceRow.innerHTML.replace( /\[choices\]\[\d+\]/g, `[choices][{{key}}]` );
|
||||
|
||||
// Clear existing choices.
|
||||
choicesList.innerHTML = '';
|
||||
|
||||
// Add new choices.
|
||||
for ( const i in choices ) {
|
||||
const key = ( Number( i ) + 1 ).toString();
|
||||
const choice = choices[ i ];
|
||||
|
||||
// Clone choice item element.
|
||||
let li = choiceRow.cloneNode( true );
|
||||
|
||||
// Get updated single choice item.
|
||||
li = this.getUpdatedSingleChoiceItem( li, key, choice );
|
||||
|
||||
// Add new choice item.
|
||||
choicesList.appendChild( li );
|
||||
}
|
||||
|
||||
// Update data-next-id attribute for choices list.
|
||||
choicesList.setAttribute( 'data-next-id', choices.length + 1 );
|
||||
|
||||
// Update field preview.
|
||||
const fieldOptions = document.getElementById( `wpforms-field-option-${ chat.fieldId }` );
|
||||
const fieldType = fieldOptions.querySelector( 'input.wpforms-field-option-hidden-type' )?.value;
|
||||
|
||||
WPFormsBuilder.fieldChoiceUpdate( fieldType, chat.fieldId, choices.length );
|
||||
WPFormsBuilder.triggerBuilderEvent( 'wpformsFieldChoiceAdd' );
|
||||
|
||||
// Trigger event after choices insert.
|
||||
chat.triggerEvent( 'wpformsAIModalAfterChoicesInsert', { fieldId: chat.fieldId } );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get updated single choice item.
|
||||
*
|
||||
* @since 1.9.1
|
||||
*
|
||||
* @param {HTMLElement} li Choice item element.
|
||||
* @param {string} key Choice key.
|
||||
* @param {string} choice Choice value.
|
||||
*
|
||||
* @return {HTMLElement} The updated choice item.
|
||||
*/
|
||||
getUpdatedSingleChoiceItem( li, key, choice ) {
|
||||
li.setAttribute( 'data-key', key.toString() );
|
||||
|
||||
// Update choice item inputs name attributes.
|
||||
li.innerHTML = li.innerHTML.replaceAll( '{{key}}', key );
|
||||
|
||||
// Sanitize choice before set.
|
||||
choice = wpf.sanitizeHTML( choice );
|
||||
|
||||
const inputDefault = li.querySelector( 'input.default' );
|
||||
|
||||
inputDefault.removeAttribute( 'checked' );
|
||||
|
||||
// Set label
|
||||
const inputLabel = li.querySelector( 'input.label' );
|
||||
|
||||
inputLabel.value = choice;
|
||||
inputLabel.setAttribute( 'value', choice );
|
||||
|
||||
// Set value.
|
||||
const inputValue = li.querySelector( 'input.value' );
|
||||
|
||||
inputValue.value = choice;
|
||||
inputValue.setAttribute( 'value', choice );
|
||||
|
||||
// Reset image upload.
|
||||
const imageUpload = li.querySelector( '.wpforms-image-upload' );
|
||||
const inputImage = imageUpload.querySelector( 'input.source' );
|
||||
|
||||
inputImage.value = '';
|
||||
inputImage.setAttribute( 'value', '' );
|
||||
imageUpload.querySelector( '.preview' ).innerHTML = '';
|
||||
imageUpload.querySelector( '.wpforms-image-upload-add' ).style.display = 'block';
|
||||
|
||||
// Reset icon choice.
|
||||
const iconSelect = li.querySelector( '.wpforms-icon-select' );
|
||||
|
||||
iconSelect.querySelector( '.ic-fa-preview' ).setAttribute( 'class', 'ic-fa-preview ic-fa-regular ic-fa-face-smile' );
|
||||
iconSelect.querySelector( 'input.source-icon' ).value = 'face-smile';
|
||||
iconSelect.querySelector( 'input.source-icon-style' ).value = 'regular';
|
||||
|
||||
return li;
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
export default function(c){return{getAnswer(e){if(e.choices?.length<1)return"";var t=[];for(const i in e.choices)t.push(`
|
||||
<li class="wpforms-ai-chat-choices-item">
|
||||
${c.htmlSpecialChars(e.choices[i])}
|
||||
</li>
|
||||
`);let r=`
|
||||
<h4>${c.htmlSpecialChars(e.heading??"")}</h4>
|
||||
<ol>
|
||||
${t.join("")}
|
||||
</ol>
|
||||
`;return c.sessionId||(r+=`<span>${c.modeStrings.footer}</span>`),r},getAnswerButtonsPre(){return`
|
||||
<button type="button" class="wpforms-ai-chat-choices-insert wpforms-ai-chat-answer-action wpforms-btn-sm wpforms-btn-orange" >
|
||||
<span>${c.modeStrings.insert}</span>
|
||||
</button>
|
||||
`},getWarningMessage(){return c.triggerEvent("wpformsAIModalBeforeWarningMessageInsert",{fieldId:c.fieldId}),`<div class="wpforms-ai-chat-divider"></div>
|
||||
<div class="wpforms-chat-item-notice">
|
||||
<div class="wpforms-chat-item-notice-content">
|
||||
<span>${c.modeStrings.warning}</span>
|
||||
</div>
|
||||
</div>`},isWelcomeScreen(){var t=document.getElementById(`wpforms-field-option-row-${c.fieldId}-choices`).querySelectorAll("li input.label");if(1!==t.length||t[0].value.trim()){if(3<t.length)return!1;var r=Object.values(c.modeStrings.defaults);for(let e=0;e<t.length;e++)if(!r.includes(t[e].value))return!1}return!0},addedAnswer(e){e.querySelector(".wpforms-ai-chat-choices-insert")?.addEventListener("click",this.insertButtonClick.bind(this))},sanitizeResponse(t){if(Array.isArray(t?.choices)){let e=t.choices;e=e.map(e=>wpf.sanitizeHTML(e,wpforms_builder.allowed_label_html_tags)),t.choices=e.filter(e=>""!==e.trim())}return t},hasProhibitedCode(e,t){return t?.choices?.length!==e?.choices?.length},insertButtonClick(e){var e=e.target.closest(".wpforms-chat-item.wpforms-chat-item-choices"),t=e?.getAttribute("data-response-id"),r=(e?.querySelector("ol")).querySelectorAll(".wpforms-ai-chat-choices-item"),i=[];for(const o in r)r.hasOwnProperty(o)&&r[o].textContent&&i.push(r[o].textContent.trim());c.wpformsAiApi.rate(!0,t),this.replaceChoices(i)},replaceChoices(e){var t=document.getElementById(`wpforms-field-option-row-${c.fieldId}-choices`).querySelector("ul.choices-list"),r=t.querySelector("li:first-child").cloneNode(!0);r.innerHTML=r.innerHTML.replace(/\[choices\]\[\d+\]/g,"[choices][{{key}}]"),t.innerHTML="";for(const l in e){var i=(Number(l)+1).toString(),o=e[l],s=r.cloneNode(!0),s=this.getUpdatedSingleChoiceItem(s,i,o);t.appendChild(s)}t.setAttribute("data-next-id",e.length+1);var n=document.getElementById("wpforms-field-option-"+c.fieldId).querySelector("input.wpforms-field-option-hidden-type")?.value;WPFormsBuilder.fieldChoiceUpdate(n,c.fieldId,e.length),WPFormsBuilder.triggerBuilderEvent("wpformsFieldChoiceAdd"),c.triggerEvent("wpformsAIModalAfterChoicesInsert",{fieldId:c.fieldId})},getUpdatedSingleChoiceItem(e,t,r){e.setAttribute("data-key",t.toString()),e.innerHTML=e.innerHTML.replaceAll("{{key}}",t),r=wpf.sanitizeHTML(r);e.querySelector("input.default").removeAttribute("checked");t=e.querySelector("input.label"),t.value=r,t.setAttribute("value",r),t=e.querySelector("input.value"),t.value=r,t.setAttribute("value",r),t=e.querySelector(".wpforms-image-upload"),r=t.querySelector("input.source"),r.value="",r.setAttribute("value",""),t.querySelector(".preview").innerHTML="",t.querySelector(".wpforms-image-upload-add").style.display="block",r=e.querySelector(".wpforms-icon-select");return r.querySelector(".ic-fa-preview").setAttribute("class","ic-fa-preview ic-fa-regular ic-fa-face-smile"),r.querySelector("input.source-icon").value="face-smile",r.querySelector("input.source-icon-style").value="regular",e}}}
|
||||
@@ -0,0 +1,248 @@
|
||||
/* global WPFormsAIChatHTMLElement, WPFormsAIFormGenerator, wpf, wpforms_builder */
|
||||
|
||||
/**
|
||||
* @param chat.modeStrings.footerFirst
|
||||
* @param chat.modeStrings.inactiveAnswerTitle
|
||||
* @param chat.preventResizeInput
|
||||
* @param response.form_title
|
||||
* @param wpforms_builder.allowed_label_html_tags
|
||||
*/
|
||||
|
||||
/**
|
||||
* The WPForms AI chat element.
|
||||
*
|
||||
* Forms mode helpers module.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*
|
||||
* @param {WPFormsAIChatHTMLElement} chat The chat element.
|
||||
*
|
||||
* @return {Object} Forms helpers object.
|
||||
*/
|
||||
export default function( chat ) { // eslint-disable-line no-unused-vars, max-lines-per-function
|
||||
/**
|
||||
* The input (textarea) height.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const inputHeight = {
|
||||
min: 54,
|
||||
max: 95,
|
||||
};
|
||||
|
||||
/**
|
||||
* The default `forms` mode helpers object.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*/
|
||||
const forms = {
|
||||
/**
|
||||
* Init `forms` mode.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*/
|
||||
init() {
|
||||
chat.input.addEventListener( 'keydown', chat.modeHelpers.keyDown );
|
||||
chat.input.addEventListener( 'keyup', chat.modeHelpers.resizeInput );
|
||||
|
||||
// Set the initial form generator state.
|
||||
if ( chat.sessionId ) {
|
||||
WPFormsAIFormGenerator.state.chatStart = true;
|
||||
|
||||
// Remove the selected state from the current template card.
|
||||
WPFormsAIFormGenerator.main.el.$templateCard
|
||||
.next( '.selected' ).removeClass( 'selected' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Detect the Enter key press.
|
||||
* Prevent resizing the input if Enter key pressed without Shift.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*
|
||||
* @param {KeyboardEvent} e The keyboard event.
|
||||
*/
|
||||
keyDown( e ) {
|
||||
chat.preventResizeInput = e.code === 'Enter' && ! e.shiftKey;
|
||||
|
||||
if ( chat.preventResizeInput ) {
|
||||
e.preventDefault();
|
||||
forms.setInputHeight( inputHeight.min );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Resize textarea while added new lines.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*/
|
||||
resizeInput() {
|
||||
if ( chat.preventResizeInput ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset style to get the correct scroll height.
|
||||
chat.input.style.height = '';
|
||||
chat.input.style.paddingTop = '10px';
|
||||
chat.input.style.paddingBottom = '10px';
|
||||
|
||||
let height;
|
||||
const scrollHeight = chat.input.scrollHeight;
|
||||
|
||||
// Calculate the height based on the scroll height.
|
||||
height = Math.min( scrollHeight, inputHeight.max );
|
||||
height = Math.max( height, inputHeight.min );
|
||||
|
||||
forms.setInputHeight( height );
|
||||
},
|
||||
|
||||
/**
|
||||
* Reset the message input field.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*/
|
||||
resetInput() {
|
||||
forms.resizeInput();
|
||||
},
|
||||
|
||||
/**
|
||||
* Set textarea height.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*
|
||||
* @param {number} height The height.
|
||||
*/
|
||||
setInputHeight( height ) {
|
||||
// Adjust padding based on the height.
|
||||
if ( height <= inputHeight.min ) {
|
||||
chat.input.style.paddingTop = '';
|
||||
chat.input.style.paddingBottom = '';
|
||||
}
|
||||
|
||||
// Set the height.
|
||||
chat.input.style.height = height + 'px';
|
||||
chat.style.setProperty( '--wpforms-ai-chat-input-height', height + 'px' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the answer based on AI response data.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*
|
||||
* @param {Object} response The AI response data.
|
||||
*
|
||||
* @return {string} HTML markup.
|
||||
*/
|
||||
getAnswer( response ) {
|
||||
if ( ! response ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const rnd = Math.floor( Math.random() * chat.modeStrings.footer.length );
|
||||
const footer = chat.modeStrings.footer[ rnd ];
|
||||
const answer = response.explanation || ( response.form_title ?? '' );
|
||||
|
||||
return `
|
||||
<h4>${ answer }</h4>
|
||||
<span>${ footer }</span>
|
||||
`;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the answer pre-buttons HTML markup.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*
|
||||
* @return {string} The answer pre-buttons HTML markup.
|
||||
*/
|
||||
getAnswerButtonsPre() {
|
||||
return `
|
||||
<button type="button" class="wpforms-ai-chat-use-form wpforms-ai-chat-answer-action wpforms-btn-sm wpforms-btn-orange" >
|
||||
<span>${ chat.modeStrings.useForm }</span>
|
||||
</button>
|
||||
`;
|
||||
},
|
||||
|
||||
/**
|
||||
* The answer was added.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*
|
||||
* @param {HTMLElement} element The answer element.
|
||||
*/
|
||||
addedAnswer( element ) { // eslint-disable-line no-unused-vars
|
||||
forms.updateInactiveAnswers();
|
||||
},
|
||||
|
||||
/**
|
||||
* Set active answer.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*
|
||||
* @param {HTMLElement} element The answer element.
|
||||
*/
|
||||
setActiveAnswer( element ) {
|
||||
forms.updateInactiveAnswers();
|
||||
|
||||
element.querySelector( '.wpforms-chat-item-content' ).setAttribute( 'title', '' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update inactive answers.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*/
|
||||
updateInactiveAnswers() {
|
||||
chat.messageList.querySelectorAll( '.wpforms-chat-item-answer:not(.active) .wpforms-chat-item-content' )
|
||||
.forEach( ( el ) => {
|
||||
// Set title attribute for inactive answers.
|
||||
el.setAttribute( 'title', chat.modeStrings.inactiveAnswerTitle );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine whether the Welcome Screen should be displayed.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*
|
||||
* @return {boolean} Display the Welcome Screen or not.
|
||||
*/
|
||||
isWelcomeScreen() {
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the message input field HTML.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*
|
||||
* @return {string} The message input field markup.
|
||||
*/
|
||||
getMessageInputField() {
|
||||
return `<textarea placeholder="${ chat.modeStrings.placeholder }"></textarea>`;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sanitize response.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*
|
||||
* @param {Object} response The response data to sanitize.
|
||||
*
|
||||
* @return {Object} The sanitized response.
|
||||
*/
|
||||
sanitizeResponse( response ) {
|
||||
if ( ! response.explanation ) {
|
||||
return response;
|
||||
}
|
||||
|
||||
// Sanitize explanation string.
|
||||
response.explanation = wpf.sanitizeHTML( response.explanation, wpforms_builder.allowed_label_html_tags );
|
||||
|
||||
return response;
|
||||
},
|
||||
};
|
||||
|
||||
return forms;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
export default function(n){const t={min:54,max:95},r={init(){n.input.addEventListener("keydown",n.modeHelpers.keyDown),n.input.addEventListener("keyup",n.modeHelpers.resizeInput),n.sessionId&&(WPFormsAIFormGenerator.state.chatStart=!0,WPFormsAIFormGenerator.main.el.$templateCard.next(".selected").removeClass("selected"))},keyDown(e){n.preventResizeInput="Enter"===e.code&&!e.shiftKey,n.preventResizeInput&&(e.preventDefault(),r.setInputHeight(t.min))},resizeInput(){var e;n.preventResizeInput||(n.input.style.height="",n.input.style.paddingTop="10px",n.input.style.paddingBottom="10px",e=n.input.scrollHeight,e=Math.min(e,t.max),e=Math.max(e,t.min),r.setInputHeight(e))},resetInput(){r.resizeInput()},setInputHeight(e){e<=t.min&&(n.input.style.paddingTop="",n.input.style.paddingBottom=""),n.input.style.height=e+"px",n.style.setProperty("--wpforms-ai-chat-input-height",e+"px")},getAnswer(e){var t;return e?(t=Math.floor(Math.random()*n.modeStrings.footer.length),t=n.modeStrings.footer[t],`
|
||||
<h4>${e.explanation||(e.form_title??"")}</h4>
|
||||
<span>${t}</span>
|
||||
`):""},getAnswerButtonsPre(){return`
|
||||
<button type="button" class="wpforms-ai-chat-use-form wpforms-ai-chat-answer-action wpforms-btn-sm wpforms-btn-orange" >
|
||||
<span>${n.modeStrings.useForm}</span>
|
||||
</button>
|
||||
`},addedAnswer(e){r.updateInactiveAnswers()},setActiveAnswer(e){r.updateInactiveAnswers(),e.querySelector(".wpforms-chat-item-content").setAttribute("title","")},updateInactiveAnswers(){n.messageList.querySelectorAll(".wpforms-chat-item-answer:not(.active) .wpforms-chat-item-content").forEach(e=>{e.setAttribute("title",n.modeStrings.inactiveAnswerTitle)})},isWelcomeScreen(){return!0},getMessageInputField(){return`<textarea placeholder="${n.modeStrings.placeholder}"></textarea>`},sanitizeResponse(e){return e.explanation&&(e.explanation=wpf.sanitizeHTML(e.explanation,wpforms_builder.allowed_label_html_tags)),e}};return r}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user