Crocoblock / suggestions

The suggestions for CrocoBlock project
195 stars 78 forks source link

JetFormbuilder - Enchantments (Code examples added) #6311

Open Lonsdale201 opened 1 year ago

Lonsdale201 commented 1 year ago

Dear Crocoblock. I have seen the requests you have just summarised, either here or in the facebook group, and I have collected them and attached sample codes in case anyone needs them.

Note that Jetfombuilder 3.0 has brought new toys and much more, so these codes, although they will continue to work in the future, are recommended to switch to the new code structures. As I have time and get these 3.0 versions ready, I will keep updating this. The notation is now "Old Style" and "New Style"

The features below are small simple add-ons that would be useful if they were to be included in JetFormBuilder sooner rather than later.

  1. Limit the selectable checkbox in the checkbox field -- Old Style // New Style Available
  2. Select all/deselect all funciton in the checkbox field -- Old Style
  3. Deselect function for the radio type field -- Old Style
  4. Character counter for the textarea field -- New Style Available
  5. Limit the repeater field -- Old Style
  6. Toggle password visibility button -- Old Style
  7. Copy a select field selected item to another text text field (placeholder cant copy) -- Old Style

Deselect function for the radio type field -> Fixed - The code has been changed to be valid only within the JFB. Amongst other things, this code was interfering with the JSF Radio filters, sorry I overlooked that.

Additional:

I've posted these before, along with example codes, I'm just pasting them here to keep them in one place:

https://github.com/Crocoblock/suggestions/issues/6159 - JetFormBuilder - Connecting two datepicker , disbale past dates - Code example added https://github.com/Crocoblock/suggestions/issues/6340 - JetFormbuilder - Media field new functions + New design (Code exmaples added) https://github.com/Crocoblock/suggestions/issues/5620 - JetFormBuilder - Disable past date in datepicker & Datetime (Code example added) https://github.com/Crocoblock/suggestions/issues/5816 - JetFormBuilder Tooltip function (Code example added)

1, Limit the selectable checkbox in the checkbox field -- Old Style The only thing, you need to add the " my_input_checkbox " classname for your checkbox field, or replace your own. Example picture: https://prnt.sc/4Megea-RF6V7 You can increase the maxChecked number. This script automatice creating a warning message. This warning message have a #warning-text2 ID so you can easy Modfily the style.

jQuery(document).ready(function ($) {
var maxChecked = 2; /* Modfily the maximum checked elements */
var checkedCount = 0;
var warningTextAdded = false;

$('.my_input_checkbox').click(function () {
if (checkedCount >= maxChecked && $(this).prop('checked')) {
$(this).prop('checked', false);
} else {
if (!$(this).prop('checked')) {
checkedCount--;
} else {
checkedCount++;
}
}
if (checkedCount < maxChecked) {
      $('#warning-text2').remove();
      warningTextAdded = false;
    } else if (!warningTextAdded) {
      var warningText = $('<div id="warning-text2">You cant select more</div>');
      $('.my_input_checkbox').last().closest('.jet-form-builder__field-wrap').append(warningText);
      warningTextAdded = true;
    }
  });
});

1, Limit the selectable checkbox in the checkbox field -- New Style

First step:

Create a new folder within your theme folder. Example image: https://prnt.sc/kNoSI0eay4r4 Add a folder name: mycustomscripts inside this folder create a new .js file : limitcheckbox.js open this file, and paste the following code (thanks to @girafffee to refactoring):

const {
          addFilter,
          addAction,
      } = JetPlugins.hooks;

const findClassName = item => item.includes( 'check-limit' );
const limitCount    = 2; /* how many checkbox can check */

addAction(
    'jet.fb.input.makeReactive',
    'jet-form-builder/checkbox-limit-restriction',
    /**
     * @param input {InputData}
     */
    function ( input ) {
        // get first checkbox node
        const [ nodeMain ] = input.nodes;

        if ( 'checkbox' !== nodeMain.type ||
            ![ ...nodeMain.classList ].some( findClassName )
        ) {
            return;
        }

        const wrapper     = nodeMain.closest( '.jet-form-builder-row' );
        const messageNode = document.createElement( 'div' );
        messageNode.classList.add( 'warning-text' );
        messageNode.innerText = 'You cant select more'; /* your message */

        // triggered at each change of the value
        input.watch( () => {
            const { length: count } = input.value.current;

            const isFull = count >= limitCount;

            for ( const node of input.nodes ) {
                if ( node.checked ) {
                    continue;
                }

                node.disabled = isFull;
            }

            if ( isFull ) {
                wrapper.append( messageNode );
            }
            else {
                messageNode.remove();
            }
        } );
    },
);

Step two open your functions.php (please use child theme!) and paste the following code:

// functions.php of your child theme or own plugin

const CHECKBOX_LIMIT_HANDLE = 'jet-fb-custom-checkbox-limit';

add_action( 'jet-form-builder/before-start-form-row', function ( \Jet_Form_Builder\Blocks\Types\Base $block ) { if ( 'checkbox-field' !== $block->get_name() ) { return; } wp_enqueue_script( CHECKBOX_LIMIT_HANDLE ); } );

add_action( 'wp_enqueue_scripts', function () { wp_register_script( CHECKBOX_LIMIT_HANDLE, get_stylesheet_directory_uri() . '/mycustomscripts/limitcheckbox.js', // for >= 3.0.0 JetFormBuilder array( 'jet-plugins' ), // for <= 2.1.11 JetFormBuilder // array() '1.0.0', true ); } );

Last step

Open your form (not the elementor) - and select your checkbox field. Exmaple image: https://prnt.sc/ec0_i4R7uzbl and add the following custom css name for your checkbox block: check-limit

2. Select all/deselect all funciton in the checkbox field -- Old Style

Before use this script you need to add a specific class for your checkbox in the jetformbuilder editor. See the example image: https://prnt.sc/-HA441Fh2m8P This script we are using the .anothercustomcheckbox if you use another class name, please replace all where you find the .anothercustomcheckbox with your own classname. Addition: Please note that the new checkbox does not follow the jetformbuilder standards, so you will need to modify the appearance of the checkbox using css. Everything is defined in the code, and you can find example css code below the script.

<script>
jQuery(document).ready(function($) {
  var newCheckbox = $('<input>', {
    type: 'checkbox',
    name: 'new_checkbox',
    value: 'new_checkbox',
    id: 'new_checkbox'
  });

  var newLabel = $('<label>', {
    for: 'new_checkbox',
    text: 'Select All',
    class: 'select-all-label'
  });

  $('.jet-form-builder__fields-group .anothercustomcheckbox:first').closest('.jet-form-builder__field-wrap').before(newCheckbox, newLabel);

  $('#new_checkbox').on('change', function() {
    // If checkbox selected
    if ($(this).is(':checked')) {
      $('.anothercustomcheckbox').prop('checked', true);
      $('.select-all-label').text('Deselect All');
    } else {
      $('.anothercustomcheckbox').prop('checked', false);
      $('.select-all-label').text('Select All');
    }
  });

  $('.anothercustomcheckbox').on('change', function() {
    // If all '.anothercustomcheckbox' checkbox selected
    if ($('.anothercustomcheckbox:not(:checked)').length === 0) {
      $('#new_checkbox').prop('checked', true);
      $('.select-all-label').text('Deselect All'); /* You can modify the custom checkbox label if all checkbox checked */
    } else {
      $('#new_checkbox').prop('checked', false);
      $('.select-all-label').text('Select All '); /* You can modify the custom checkbox label */
    }
  });
});
</script>

<style>
  #new_checkbox {
  display: none; /* hide the default checkbox */
}

#new_checkbox + label::before {
 content: "";
    display: inline-block;
    width: 1.2em;
    height: 1.2em;
    flex-shrink: 0;
    flex-grow: 0;
    border: 1px solid #adb5bd;
    margin-right: 0.5em;
    background-repeat: no-repeat;
    background-position: center center;
    background-size: 50% 50%;
}

#new_checkbox:checked + label::before {
  border-color: #0b76ef;
    background-color: #0b76ef;
   background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e");
/* This is the same check icon like using the JFB */
}
 label[for="new_checkbox"] {
    display: inline-flex;
    align-items: center;
    font-size: 16px;
    font-family: 'Roboto';
    padding-bottom: 10px;

}    
</style>

3. Deselect function for the radio type field -- Old Style

    jQuery(document).ready(function ($) {
  $('.jet-form-builder label:has(input[type=radio])').on('mousedown', function(e){
    var radio = $(this).find('input[type=radio]');
    var wasChecked = radio.prop('checked');
    radio[0].turnOff = wasChecked;
    radio.prop('checked', !wasChecked);
  });

  $('.jet-form-builder label:has(input[type=radio])').on('click', function(e){
    var radio = $(this).find('input[type=radio]');
    radio.prop('checked', !radio[0].turnOff);
    radio[0]['turning-off'] = !radio[0].turnOff;
  });
});

Character counter for the textarea field -- Old Style + New Style (Jetformbuilder 3.0 and above)

This code automatice detect your max character limit, so you only need to localize your FORM FIELD NAME Example Picture: https://prnt.sc/Ez8FklyRDEIZ So replace the #mytextarea with your own, or you can use my ID.

The code automatice create a new Class "my_charactercounter" - and will populate the max character, and the counter. This counter will appear, below your textarea field. The code also detects when the maximum number of characters entered reaches 80% and the counter turns red. You can overwrite the percentage value yourself and freely change the appearance.

If you're interested in how to make the character counter compatible with JetFormbuilder's save form progress add-on (Recommended only advanced users) - I've created an initial example code to get you started, you can find it here: https://www.codepile.net/pile/j0pJDqPJ

-- New Style

With the New JFB Update (3.0) You no longer need the code below. How can you do the character counter with the JetFormbilder 3.0?

Drop a calcuated field under your textarea field and copy the following macro: %myformfieldname(remaining)% OR

You can use the following macro and you can paste in the form field description if you want:

just replace my formfieldname with your own. The only thing you need to change in the macro is myformfieldname - to the Form Field Name you named it (your textare block) -- Old Style ``` jQuery(document).ready(function($) { const $textarea = $('#mytextarea'); const maxLength = $textarea.attr('maxlength'); const threshold = maxLength * 0.8; const $counter = $('

').addClass('my_charactercounter'); $counter.text(`${$textarea.val().length}/${maxLength} karakter`); $textarea.on('input', function() { if ($(this).val().length > maxLength) { $(this).val($(this).val().substring(0, maxLength)); } $counter.text(`${$(this).val().length}/${maxLength} karakter`); if ($(this).val().length >= threshold) { $counter.css('color', 'red'); } else { $counter.css('color', ''); } }); $textarea.after($counter); }); ``` **5, Limit the repeater field** The only thing that you need to add your custom class like in the picture: https://prnt.sc/A_2M7ahL8ZLm ``` jQuery(document).ready(function($) { $('.limitedrepeater').on('click', '.jet-form-builder-repeater__new, .jet-form-builder-repeater__remove', function() { var rowCount = $('.limitedrepeater .jet-form-builder-repeater__row').length; var maxRows = 3; if (this.className.includes('remove') && rowCount > 0) { rowCount--; } if (rowCount >= maxRows) { $('.limitedrepeater .jet-form-builder-repeater__new').css('opacity', '0.5'); $('.limitedrepeater .jet-form-builder-repeater__new').prop('disabled', true); } else { $('.limitedrepeater .jet-form-builder-repeater__new').css('opacity', '1'); $('.limitedrepeater .jet-form-builder-repeater__new').prop('disabled', false); } }); }); ``` **Toggle password visibility button** No extra steps are needed. In this code, it finds the first password field type within the .jet-form-builder__field-wrap class and adds the password display button. ``` jQuery(document).ready(function($) { const $passwordInput = $('input[type="password"]').first(); const $container = $passwordInput.closest('.jet-form-builder__field-wrap'); const $showHideButton = $(''); $container.append($showHideButton); $showHideButton.on('click', function(event) { event.preventDefault(); if ($passwordInput.attr('type') === 'password') { $passwordInput.attr('type', 'text'); $showHideButton.html(''); } else { $passwordInput.attr('type', 'password'); $showHideButton.html(''); } }); }); ``` ![image](https://user-images.githubusercontent.com/23199033/210137219-5d1d2eca-4721-4a93-ab2f-febc4625152b.png) ![image](https://user-images.githubusercontent.com/23199033/210137224-b685fbc9-f02b-4ed0-8b17-a3b45ed271b3.png) **7, Copy a select field selected item to another text text field (placeholder cant copy)** - Only support single value ``` window.addEventListener('load', function() { const telepulesElement = document.querySelector('#telepules'); /* ('#telepules'); Replace with your own Select field - FORM FIELD NAME */ if (!telepulesElement) return; telepulesElement.addEventListener('change', function() { const options = this.options; const selectedOptionValue = options[options.selectedIndex].value; if (selectedOptionValue !== '') { document.querySelector('#allat_elveszett_hol').value = options[options.selectedIndex].text; /* ('#allat_elveszett_hol') Replace with your own Text field - FORM FIELD NAME */ } }); }); ```

girafffee commented 1 year ago

Hi, @Lonsdale201. I appreciate your input in developing new features. I would like to inform you that a couple of the features you listed have already been implemented within the new version of JetFormBuilder (the release is expected next year). More specifically, we are talking about:

As for other features, their implementation will require a completely different approach to writing code. That is, I mean that your code will most likely work even after the release of a major version, but I will be able to offer a cleaner solution.

For example, to limit the number of selected checkboxes, we can write as follows:

let { addAction } = JetPlugins.hooks;
let checkboxLimit = 4;

addAction(
    'jet.fb.input.makeReactive',
    'jet-fb/custom',
    input => {
        const [ node ] = input.nodes;

        if ( !node.classList.contains( 'checkboxes-field' ) ) {
            return;
        }

        input.sanitize( value => value.slice( 0, checkboxLimit ) );
    }
);

Of course, this solution is very simple, which is why it has disadvantages compared to yours.

With your permission, I can take your code as a basis and rework it for the new version of the plugin. This will be a good example of migration of custom solutions. You can see the result on the wiki page in the Crocoblock/jetformbuilder repository

Lonsdale201 commented 1 year ago

Hi, @Lonsdale201. I appreciate your input in developing new features. I would like to inform you that a couple of the features you listed have already been implemented within the new version of JetFormBuilder (the release is expected next year). More specifically, we are talking about:

  • Character counter for the textarea field
  • Connecting two datepickers, disbale past dates

As for other features, their implementation will require a completely different approach to writing code. That is, I mean that your code will most likely work even after the release of a major version, but I will be able to offer a cleaner solution.

For example, to limit the number of selected checkboxes, we can write as follows:

let { addAction } = JetPlugins.hooks;
let checkboxLimit = 4;

addAction(
  'jet.fb.input.makeReactive',
  'jet-fb/custom',
  input => {
      const [ node ] = input.nodes;

      if ( !node.classList.contains( 'checkboxes-field' ) ) {
          return;
      }

      input.sanitize( value => value.slice( 0, checkboxLimit ) );
  }
);

Of course, this solution is very simple, which is why it has disadvantages compared to yours.

With your permission, I can take your code as a basis and rework it for the new version of the plugin. This will be a good example of migration of custom solutions. You can see the result on the wiki page in the Crocoblock/jetformbuilder repository

I am happy that new features will be coming. Basically, when a client requests a feature that is not included in a particular extension, I add it. And I often post them here on github, but the code is mostly not for you, because you are developing in a different structure, so it might be less suitable for you, but if you can use some of it, I'm happy. Basically, I'm sharing the addition so that others can use it if they need something similar, even if only temporarily.

Lonsdale201 commented 1 year ago

Hi, @Lonsdale201. I appreciate your input in developing new features. I would like to inform you that a couple of the features you listed have already been implemented within the new version of JetFormBuilder (the release is expected next year). More specifically, we are talking about:

  • Character counter for the textarea field
  • Connecting two datepickers, disbale past dates

As for other features, their implementation will require a completely different approach to writing code. That is, I mean that your code will most likely work even after the release of a major version, but I will be able to offer a cleaner solution.

For example, to limit the number of selected checkboxes, we can write as follows:

let { addAction } = JetPlugins.hooks;
let checkboxLimit = 4;

addAction(
  'jet.fb.input.makeReactive',
  'jet-fb/custom',
  input => {
      const [ node ] = input.nodes;

      if ( !node.classList.contains( 'checkboxes-field' ) ) {
          return;
      }

      input.sanitize( value => value.slice( 0, checkboxLimit ) );
  }
);

Of course, this solution is very simple, which is why it has disadvantages compared to yours.

With your permission, I can take your code as a basis and rework it for the new version of the plugin. This will be a good example of migration of custom solutions. You can see the result on the wiki page in the Crocoblock/jetformbuilder repository

What I haven't been able to solve yet, although I'm not giving up, is clearing the html parts from the input field. I've been struggling with the problem for some time to get the html values out of the input data, because unfortunately JFB doesn't clean them, so unintentionally if someone fills out a form, he can enter different html parts into the fields and these can affect the front end display. I've tried to approach it from several directions, running JS , hook, and backend side, but no real solution yet. Will there even be a function to enable html cleanup in the future?

girafffee commented 1 year ago

Will there even be a function to enable html cleanup in the future?

Yes, this feature is already in our roadmap

Lonsdale201 commented 1 year ago

Will there even be a function to enable html cleanup in the future?

Yes, this feature is already in our roadmap

Thank you. I have meanwhile extended this description with a new password display/hide code. This is another funciton that is cool and useful, I hope it will be part of JFB one day (obviously it's a low priority thing).

And coming back, of course, if there is anything useful in this code and you can use it, of course. Happy New Year. :)

Lonsdale201 commented 1 year ago

Radio deselect function script fixed. Added a new script : Copy a select field selected item to another text text field

girafffee commented 1 year ago

With the New JFB Update (3.0) You no longer need the code below. How can you do the character counter with the JetFormbilder 3.0?

Drop a calcuated field under your textarea field and copy the following macro:

%myformfieldname(remaining)%

Note that you can use the following construct <!--JFB_FIELD::[any_macro]-->.

In your case, the macro will look like this: <!--JFB_FIELD::myformfieldname(remaining)-->

Lonsdale201 commented 1 year ago

With the New JFB Update (3.0) You no longer need the code below. How can you do the character counter with the JetFormbilder 3.0? Drop a calcuated field under your textarea field and copy the following macro: %myformfieldname(remaining)%

Note that you can use the following construct <!--JFB_FIELD::[any_macro]-->.

In your case, the macro will look like this: <!--JFB_FIELD::myformfieldname(remaining)-->

Yes updated, thx :)

lifeact commented 11 months ago

girafffee

Will there even be a function to enable html cleanup in the future?

Yes, this feature is already in our roadmap

Hi, limit the number of selected checkboxes is not ready yet?

If no,:

`let { addAction } = JetPlugins.hooks; let checkboxLimit = 4;

addAction( 'jet.fb.input.makeReactive', 'jet-fb/custom', input => { const [ node ] = input.nodes;

    if ( !node.classList.contains( 'checkboxes-field' ) ) {
        return;
    }

    input.sanitize( value => value.slice( 0, checkboxLimit ) );
}

);`

where insert this code? Just in function.php?

ironwiller commented 10 months ago

hi! first of thanks both @Lonsdale201 and @girafffee for the scripts and guides.

Is there a way to have for the no 1. (checkbox) two limits in the same time? for ex, 2 and 3 (the first for one checkbox and the second for another one) as well for any of them to be mandatory to select 2 or 3 (optional and addition to the above)

I've tried replicating the code as below:

  1. by creating another file "limitcheckbox3.js" 1.a. changing the findClassName to "check-limit-3" from "check-limit" 1.b. changing the limitCountto 3 from 2 (that i had initially)

  2. at function.php I've c/p the code above after the initial code by changing the following to it: 2.a. wherever exists from "CHECKBOX_LIMIT_HANDLE" i made it "CHECKBOX_LIMIT_HANDLE_3" 2.b. directory URL from "limitcheckbox.js" to "limitcheckbox3.js"

Obviously something I'm missing editing since i don't know some other parameters and also perhaps the above could be done easier by adding to the initial file some additional if.

Can you please guide me how to?

Thanks in advance!