Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhance: post form builder settings #1513

Open
wants to merge 112 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 111 commits
Commits
Show all changes
112 commits
Select commit Hold shift + click to select a range
63151b3
initial header style
sapayth Oct 7, 2024
787c082
preview and save buttons
sapayth Oct 7, 2024
a7c5fe7
dropdown effect enhanced
sapayth Oct 9, 2024
d008e8a
shortcode copy icon enhanced
sapayth Oct 9, 2024
c96afbf
backward compatibility added for old wpuf pro
sapayth Oct 10, 2024
065b1fa
update copy shortcode icon
sapayth Oct 10, 2024
6607241
Merge branch 'develop' into enhance/header_for_form_builder_ui_redesign
sapayth Oct 21, 2024
ab3ce2c
type and image fixing
sapayth Oct 22, 2024
3eba5a0
Merge remote-tracking branch 'upstream/develop' into enhance/header_f…
sapayth Oct 31, 2024
7293f64
updated form builder header design
sapayth Nov 8, 2024
fe34c3b
nav css
sapayth Nov 8, 2024
ab36c5c
Squashed commit of the following:
sapayth Nov 8, 2024
6a93fc4
Merge remote-tracking branch 'upstream/develop' into enhance/new_buil…
sapayth Nov 11, 2024
dbef1af
initial design
sapayth Nov 12, 2024
ab32ffd
hidden fields and other small css
sapayth Nov 13, 2024
ed4b378
column field
sapayth Nov 13, 2024
d02c221
Merge remote-tracking branch 'upstream/develop' into enhance/new_buil…
sapayth Nov 13, 2024
bc50028
Merge remote-tracking branch 'upstream/develop' into enhance/new_buil…
sapayth Nov 14, 2024
3b59cbc
column fields initial rendering
sapayth Nov 15, 2024
4443867
column field initial
sapayth Nov 25, 2024
aa1c0d8
fix action buttons move action
sapayth Nov 25, 2024
aa9f072
icon for featured image
sapayth Nov 25, 2024
21d19c2
icon for image upload button
sapayth Nov 25, 2024
87f577d
Merge remote-tracking branch 'upstream/develop' into enhance/new_buil…
sapayth Nov 26, 2024
ac5db7e
backward compatibility for pro version
sapayth Nov 26, 2024
3df5eeb
compatibility for settings and notification tab
sapayth Nov 26, 2024
bf99c43
initial modal
sapayth Nov 26, 2024
b8db203
dynamic templates and hover effects
sapayth Nov 27, 2024
9b4437f
add test for form modal
sapayth Nov 27, 2024
35b9fcf
add fields initial design
sapayth Dec 2, 2024
2a1ce0b
search field functionality
sapayth Dec 3, 2024
ba23a52
dynamic search and clear icon
sapayth Dec 3, 2024
56e9a33
pro fields icon and styling
sapayth Dec 3, 2024
e3f9a4f
post content field
sapayth Dec 5, 2024
7ab496b
highlight selected field
sapayth Dec 6, 2024
6710ad9
select, multi-select, content restriction
sapayth Dec 6, 2024
0363606
select fields
sapayth Dec 9, 2024
cbe19ad
dropdown field
sapayth Dec 9, 2024
178f8f0
dropdown options
sapayth Dec 10, 2024
b978ab5
enhance recaptcha field
sapayth Dec 11, 2024
3aaa5de
fix multiple fields
sapayth Dec 12, 2024
d626f9b
reg form backward compatibility
sapayth Dec 17, 2024
e5201fc
backward compatibility
sapayth Dec 17, 2024
90c62f9
css fixes
sapayth Dec 19, 2024
286a488
js warning
sapayth Dec 20, 2024
f561dd1
qa followup 1 to 25
sapayth Dec 26, 2024
6657551
dragging inside column field
sapayth Dec 27, 2024
689dd70
icons, blank state
sapayth Jan 1, 2025
b06bc5c
fix dropdown list css
sapayth Jan 1, 2025
5139424
fix dragging after field search
sapayth Jan 2, 2025
579dba6
add canny link for new field
sapayth Jan 2, 2025
4b65706
pro field supports
sapayth Jan 6, 2025
ad480f8
hidden fields
sapayth Jan 7, 2025
879ee1b
dropdown options, show values, sync values design
sapayth Jan 9, 2025
ceb6a49
fix radio css
sapayth Jan 9, 2025
78bcb6a
hide multistep toggle on free
sapayth Jan 9, 2025
1617bf1
merge mixins
sapayth Jan 10, 2025
9090d49
field size preview
sapayth Jan 10, 2025
1f2ef53
initial general setup
sapayth Jan 14, 2025
0d7503d
support multi-select field
sapayth Jan 15, 2025
97ee3e6
settings: form template field
sapayth Jan 16, 2025
15246dd
togglebar for multi-step
sapayth Jan 17, 2025
8feaa95
multistep text color, active bg color, bg color
sapayth Jan 20, 2025
b688177
after post settings
sapayth Jan 20, 2025
877eb34
posting control fields and conditionals
sapayth Jan 22, 2025
e4e1bce
multistep conditional
sapayth Jan 22, 2025
66a0cbd
dropdown options UI with show values fixed
sapayth Jan 23, 2025
9afb324
initial pro field popup
sapayth Jan 27, 2025
ba9490f
transient added for optimization
sapayth Jan 27, 2025
d25c9fb
show custom field
sapayth Jan 28, 2025
55e1d57
dependency popups
sapayth Jan 28, 2025
8f061ec
field inside column
sapayth Jan 29, 2025
3afd959
remove appsero unwanted data
sapayth Jan 29, 2025
e9eb64b
initial payment settings
sapayth Jan 30, 2025
16350f3
conditionally show/hide
sapayth Jan 30, 2025
d0be557
toggle button style enhancement
sapayth Jan 31, 2025
208553d
notification settings design
sapayth Feb 3, 2025
7361839
show multistep fields initial value
sapayth Feb 4, 2025
eada9c6
initial conditional fields status
sapayth Feb 5, 2025
69c6621
dropdown show values, sync values
sapayth Feb 7, 2025
584c78e
radio field, select field
sapayth Feb 7, 2025
854c8ab
hidden fields css fix
sapayth Feb 11, 2025
4e82c44
field option, column range
sapayth Feb 12, 2025
9095cba
field options data
sapayth Feb 12, 2025
f46f83c
fix pro link
sapayth Feb 12, 2025
259e856
Merge branch 'enhance/form_fields_promo_popup_and_modals' into enhanc…
sapayth Feb 12, 2025
c341f35
conditional default post category
sapayth Feb 12, 2025
9f80024
retrieve categories based on post type
sapayth Feb 13, 2025
f248ead
dynamic field based on successful redirection
sapayth Feb 13, 2025
981f1a2
Choose who can submit post
sapayth Feb 13, 2025
d916542
template modal, form builder header
sapayth Feb 14, 2025
003c704
form builder display settings
sapayth Feb 17, 2025
bff9194
initial pro fields preview
sapayth Feb 17, 2025
2937533
multistep pro preview
sapayth Feb 17, 2025
3e0aa6f
pro fields preview
sapayth Feb 17, 2025
3d8c78b
display settings: form styles preview
sapayth Feb 18, 2025
0e468ab
form scheduling dates
sapayth Feb 18, 2025
6e6d2a5
modules pro preview
sapayth Feb 18, 2025
a10101d
upgrade to pro button
sapayth Feb 18, 2025
e1eba28
extending settings with filter hook
sapayth Feb 19, 2025
13f4db4
modules menu item css fixes
sapayth Feb 19, 2025
9b591c7
show/hide dependent fields conditionally
sapayth Feb 20, 2025
ff514f3
cleanup
sapayth Feb 20, 2025
2e51588
attach FormDependencyHandler to window for reusing
sapayth Feb 20, 2025
9711274
tooltips updated
sapayth Feb 20, 2025
982af8a
form builder header enhanced
sapayth Feb 24, 2025
cebe79a
radio field css
sapayth Feb 27, 2025
6fa7d51
dropdown css
sapayth Feb 27, 2025
0d0a593
mixed css fixes
sapayth Mar 3, 2025
cbdbfe4
registration form general settings
sapayth Mar 3, 2025
ce6d438
condition on radio fields
sapayth Mar 5, 2025
ddcccee
fix help texts
sapayth Mar 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 52 additions & 2 deletions Gruntfile.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
'use strict';
module.exports = function(grunt) {
module.exports = function( grunt) {
const tailwindFileMap = {
'admin/form-builder/views/form-builder-v4.1.php': 'admin/form-builder.css',
'admin/form-builder/views/post-form-settings.php': 'admin/form-builder.css',
}

var formBuilderAssets = require('./admin/form-builder/assets/js/form-builder-assets.js');

var pkg = grunt.file.readJSON('package.json');
Expand Down Expand Up @@ -112,7 +117,22 @@ module.exports = function(grunt) {
tasks: [
'shell:npm_build'
]
}
},

tailwind: {
files: [
'src/css/**/*.css',
'admin/form-builder/views/*.php',
'admin/form-builder/assets/js/**/*.php',
'admin/form-builder/assets/js/**/*.js',
'includes/Admin/**/*.php',
'wpuf-functions.php',
],
tasks: ['shell:tailwind:src/css/admin/form-builder.css:assets/css/admin/form-builder.css'],
options: {
spawn: false
}
},
},

// Clean up build directory
Expand Down Expand Up @@ -224,6 +244,11 @@ module.exports = function(grunt) {
shell: {
npm_build: {
command: 'npm run build',
},
tailwind: {
command: function ( input, output ) {
return `npx tailwindcss -i ${input} -o ${output}`;
}
}
Comment on lines +248 to 252
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add validation for Tailwind CLI input and output paths.

The current implementation doesn't validate the input and output paths before executing the Tailwind CLI command. This could lead to errors if the paths contain spaces or special characters.

 tailwind: {
     command: function ( input, output ) {
-        return `npx tailwindcss -i ${input} -o ${output}`;
+        // Validate and sanitize input and output paths
+        const sanitizedInput = input.replace(/[^a-zA-Z0-9/\-_.]/g, '');
+        const sanitizedOutput = output.replace(/[^a-zA-Z0-9/\-_.]/g, '');
+        
+        if (sanitizedInput !== input || sanitizedOutput !== output) {
+            grunt.log.warn('Input or output paths contain invalid characters and were sanitized.');
+        }
+        
+        return `npx tailwindcss -i "${sanitizedInput}" -o "${sanitizedOutput}"`;
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
tailwind: {
command: function ( input, output ) {
return `npx tailwindcss -i ${input} -o ${output}`;
}
}
tailwind: {
command: function ( input, output ) {
// Validate and sanitize input and output paths
const sanitizedInput = input.replace(/[^a-zA-Z0-9/\-_.]/g, '');
const sanitizedOutput = output.replace(/[^a-zA-Z0-9/\-_.]/g, '');
if (sanitizedInput !== input || sanitizedOutput !== output) {
grunt.log.warn('Input or output paths contain invalid characters and were sanitized.');
}
return `npx tailwindcss -i "${sanitizedInput}" -o "${sanitizedOutput}"`;
}
}

}
});
Expand All @@ -241,6 +266,7 @@ module.exports = function(grunt) {
grunt.loadNpmTasks( 'grunt-notify' );
grunt.loadNpmTasks( 'grunt-wp-readme-to-markdown' );
grunt.loadNpmTasks( 'grunt-shell' );
grunt.loadNpmTasks( 'grunt-postcss' );

grunt.registerTask( 'default', [ 'less', 'concat', 'uglify', 'i18n' ] );

Expand All @@ -251,4 +277,28 @@ module.exports = function(grunt) {
// build stuff
grunt.registerTask( 'release', [ 'less', 'concat', 'uglify', 'i18n', 'readme' ] );
grunt.registerTask( 'zip', [ 'clean', 'copy', 'compress' ] );

grunt.event.on('watch', function(action, filepath, target) {
if (target === 'tailwind') {
grunt.task.run('tailwind');
}
});

grunt.registerTask('tailwind', function() {
const done = this.async();

// Process each file mapping
Object.entries(tailwindFileMap).forEach(([phpFile, cssFile]) => {
const inputFile = `src/css/${cssFile}`;
const outputFile = `assets/css/${cssFile}`;

// Ensure the input file exists
if (grunt.file.exists(inputFile)) {
// Run the tailwind command
grunt.task.run(`shell:tailwind:${inputFile}:${outputFile}`);
}
});

done();
});
Comment on lines +287 to +303
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling to the tailwind task.

The tailwind task lacks error handling for file operations and shell command execution.

 grunt.registerTask('tailwind', function() {
     const done = this.async();
+    let hasErrors = false;

     // Process each file mapping
     Object.entries(tailwindFileMap).forEach(([phpFile, cssFile]) => {
         const inputFile = `src/css/${cssFile}`;
         const outputFile = `assets/css/${cssFile}`;

         // Ensure the input file exists
-        if (grunt.file.exists(inputFile)) {
+        try {
+            if (!grunt.file.exists(inputFile)) {
+                grunt.log.error(`Input file ${inputFile} does not exist`);
+                hasErrors = true;
+                return;
+            }

+            // Ensure the output directory exists
+            const outputDir = require('path').dirname(outputFile);
+            if (!grunt.file.exists(outputDir)) {
+                grunt.file.mkdir(outputDir);
+            }

             // Run the tailwind command
             grunt.task.run(`shell:tailwind:${inputFile}:${outputFile}`);
+        } catch (error) {
+            grunt.log.error(`Error processing ${inputFile}: ${error.message}`);
+            hasErrors = true;
+        }
     });

-    done();
+    done(!hasErrors);
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
grunt.registerTask('tailwind', function() {
const done = this.async();
// Process each file mapping
Object.entries(tailwindFileMap).forEach(([phpFile, cssFile]) => {
const inputFile = `src/css/${cssFile}`;
const outputFile = `assets/css/${cssFile}`;
// Ensure the input file exists
if (grunt.file.exists(inputFile)) {
// Run the tailwind command
grunt.task.run(`shell:tailwind:${inputFile}:${outputFile}`);
}
});
done();
});
grunt.registerTask('tailwind', function() {
const done = this.async();
let hasErrors = false;
// Process each file mapping
Object.entries(tailwindFileMap).forEach(([phpFile, cssFile]) => {
const inputFile = `src/css/${cssFile}`;
const outputFile = `assets/css/${cssFile}`;
// Ensure the input file exists
try {
if (!grunt.file.exists(inputFile)) {
grunt.log.error(`Input file ${inputFile} does not exist`);
hasErrors = true;
return;
}
// Ensure the output directory exists
const outputDir = require('path').dirname(outputFile);
if (!grunt.file.exists(outputDir)) {
grunt.file.mkdir(outputDir);
}
// Run the tailwind command
grunt.task.run(`shell:tailwind:${inputFile}:${outputFile}`);
} catch (error) {
grunt.log.error(`Error processing ${inputFile}: ${error.message}`);
hasErrors = true;
}
});
done(!hasErrors);
});

};
2 changes: 1 addition & 1 deletion Lib/Appsero/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ protected function set_basename_and_slug() {

require_once ABSPATH . 'wp-admin/includes/plugin.php';

$plugin_data = get_plugin_data( $this->file );
$plugin_data = get_plugin_data( $this->file, true, false );

$this->project_version = $plugin_data['Version'];
$this->type = 'plugin';
Expand Down
179 changes: 179 additions & 0 deletions admin/form-builder/assets/js/components/builder-stage-v4-1/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
Vue.component('builder-stage-v4-1', {
template: '#tmpl-wpuf-builder-stage-v4-1',

mixins: wpuf_form_builder_mixins(wpuf_mixins.builder_stage).concat(wpuf_mixins.add_form_field),

computed: {
form_fields: function () {
return this.$store.state.form_fields;
},

field_settings: function () {
return this.$store.state.field_settings;
},

hidden_fields: function () {
return this.$store.state.form_fields.filter(function (item) {
return 'custom_hidden_field' === item.template;
});
},

editing_form_id: function () {
return this.$store.state.editing_field_id;
},
},

mounted: function () {
var self = this,
in_column_field = false;

// bind jquery ui sortable
$('#form-preview-stage, #form-preview-stage .wpuf-form.sortable-list').sortable({
placeholder: 'form-preview-stage-dropzone',
items: '.field-items',
handle: '.field-buttons .move',
scroll: true,
over: function() {
in_column_field = false;

// if the field drop in column field, then stop field rendering in the builder stage
$(".wpuf-column-inner-fields" ).on( "drop", function(event) {
var targetColumn = event.currentTarget.classList,
isColumnExist = $.inArray(".wpuf-column-inner-fields", targetColumn);

if ( isColumnExist ) {
in_column_field = true;
}
} );
},
update: function (e, ui) {
var item = ui.item[0],
data = item.dataset,
source = data.source,
toIndex = parseInt($(ui.item).index()),
payload = {
toIndex: toIndex
};

if ('panel' === source) {
// add new form element
self.$store.state.index_to_insert = parseInt(toIndex);

if ( ! in_column_field ) {
var field_template = ui.item[0].dataset.formField;
self.add_form_field(field_template);
}

// remove button from stage
$(this).find('.wpuf-field-button').remove();

} else if ('stage' === source) {
payload.fromIndex = parseInt(data.index);

self.$store.commit('swap_form_field_elements', payload);
}

}
});
},

methods: {
open_field_settings: function(field_id) {
this.$store.commit('open_field_settings', field_id);
},

clone_field: function(field_id, index) {
var payload = {
field_id: field_id,
index: index,
new_id: this.get_random_id()
};

// single instance checking
var field = _.find(this.$store.state.form_fields, function (item) {
return parseInt(item.id) === parseInt(payload.field_id);
});

// check if these are already inserted
if ( this.isSingleInstance( field.template ) && this.containsField( field.template ) ) {
Swal.fire({
title: "Oops...",
text: "You already have this field in the form"
});
return;
}

this.$store.commit('clone_form_field_element', payload);
},

delete_field: function(index) {
var self = this;

(Swal.fire({
text: self.i18n.delete_field_warn_msg,
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d54e21',
confirmButtonText: self.i18n.yes_delete_it,
cancelButtonText: self.i18n.no_cancel_it,
customClass: {
confirmButton: 'btn btn-success',
cancelButton: 'btn btn-danger',
}
})).then((result) => {
if (result.isConfirmed) {
self.$store.commit('delete_form_field_element', index);
}
});
},

delete_hidden_field: function (field_id) {
var i = 0;

for (i = 0; i < this.form_fields.length; i++) {
if (parseInt(field_id) === parseInt(this.form_fields[i].id)) {
this.delete_field(i);
}
}
},

is_pro_feature: function (template) {
return ( this.field_settings[template] && this.field_settings[template].pro_feature ) ? true : false;
},

is_template_available: function (field) {
var template = field.template;

if (this.field_settings[template]) {
if (this.is_pro_preview(template)) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix incorrect method name.

The method is_pro_preview is called but is_pro_feature is defined. This will cause a runtime error.

-                if (this.is_pro_preview(template)) {
+                if (this.is_pro_feature(template)) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (this.is_pro_preview(template)) {
if (this.is_pro_feature(template)) {

return false;
}

return true;
}

// for example see 'mixin_builder_stage' mixin's 'is_taxonomy_template_available' method
if (_.isFunction(this['is_' + template + '_template_available'])) {
return this['is_' + template + '_template_available'].call(this, field);
}

return false;
},

is_full_width: function (template) {
if (this.field_settings[template] && this.field_settings[template].is_full_width) {
return true;
}

return false;
},

is_invisible: function (field) {
return ( field.recaptcha_type && 'invisible_recaptcha' === field.recaptcha_type ) ? true : false;
},

get_field_name: function (template) {
return this.field_settings[template].title;
}
}
});
Loading
Loading