From 604357b9659a6654fd7ebf92cbe1f4cdfacbdb31 Mon Sep 17 00:00:00 2001 From: Eduardo Date: Tue, 7 Jan 2025 01:15:44 -0300 Subject: [PATCH 01/11] chore: change php minimum version --- form-masks-for-elementor.php | 8 ++++---- readme.txt | 13 +++++++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/form-masks-for-elementor.php b/form-masks-for-elementor.php index d707cb4..2c86975 100644 --- a/form-masks-for-elementor.php +++ b/form-masks-for-elementor.php @@ -5,9 +5,9 @@ * Description: Form Masks for Elementor create a custom control in field advanced tab for your customize your fields with masks. This plugin require the Elementor Pro (Form Widget). * Author: EduardoVillao.me * Author URI: https://eduardovillao.me/ - * Version: 1.6.5 + * Version: 2.0 * Requires at least: 5.5 - * Requires PHP: 7.0 + * Requires PHP: 7.4 * Text Domain: form-masks-for-elementor * License: GPL-2.0+ * License URI: http://www.gnu.org/licenses/gpl-2.0.txt @@ -34,8 +34,8 @@ define( 'FME_PLUGIN_PATH', plugin_dir_path( __FILE__ ) ); define( 'FME_PLUGN_URL', plugin_dir_url( __FILE__ ) ); -define( 'FME_VERSION' , '1.6.5' ); -define( 'FME_PHP_MINIMUM_VERSION', '7.0' ); +define( 'FME_VERSION' , '2.0' ); +define( 'FME_PHP_MINIMUM_VERSION', '7.4' ); define( 'FME_WP_MINIMUM_VERSION', '5.5' ); /** diff --git a/readme.txt b/readme.txt index 608e5b7..e843933 100644 --- a/readme.txt +++ b/readme.txt @@ -1,11 +1,11 @@ === Form Masks for Elementor === Contributors: evcode Donate link: https://eduardovillao.me/ -Tags: elementor, form, mask, elementor mask, formulario, form mask +Tags: elementor, elementor form, form mask Requires at least: 5.5 Tested up to: 6.7 -Stable tag: 1.6.5 -Requires PHP: 7.0 +Stable tag: 2.0 +Requires PHP: 7.4 License: GPLv2License URI:https://www.gnu.org/licenses/gpl-2.0.html @@ -85,10 +85,15 @@ Please, send to me: [plugins@eduardovillao.me](mailto:plugins@eduardovillao.me) == Changelog == += 2.0 = +* Changed: minimum PHP version changed to 7.4. +* Changed: improve build proccess to assets. + += 1.6.5 = * Changed: compatibility with WordPress 6.7. * Changed: code improvements. -= 1.6.5 = += 1.6.4 = * Changed: compatibility with WordPress 6.5. * Changed: code improvements. From 94063d22b063121e37b20bcab9d6e099e4280141 Mon Sep 17 00:00:00 2001 From: Eduardo Date: Tue, 7 Jan 2025 01:23:23 -0300 Subject: [PATCH 02/11] chore: update packages to latest --- package.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 005a560..d13d12a 100644 --- a/package.json +++ b/package.json @@ -18,12 +18,12 @@ }, "homepage": "https://github.com/eduardovillao/myd-delivery-pro#readme", "devDependencies": { - "@wordpress/eslint-plugin": "18.0.0", - "css-loader": "7.1.2", - "css-minimizer-webpack-plugin": "7.0.0", - "esbuild-loader": "4.1.0", - "mini-css-extract-plugin": "2.9.0", - "webpack": "5.91.0", - "webpack-cli": "5.1.4" + "@wordpress/eslint-plugin": "^22.1.1", + "css-loader": "^7.1.2", + "css-minimizer-webpack-plugin": "^7.0.0", + "esbuild-loader": "^4.2.2", + "mini-css-extract-plugin": "^2.9.2", + "webpack": "^5.97.1", + "webpack-cli": "^6.0.1" } } From e6c7eec107bc0256ff1b424b4f6bb4e9638a24db Mon Sep 17 00:00:00 2001 From: Eduardo Date: Tue, 7 Jan 2025 01:29:48 -0300 Subject: [PATCH 03/11] chore: config webpack and create build js asset --- assets/js/elementor-mask.min.js | 1 + includes/class-elementor-mask-control.php | 30 +-- includes/class-fme-plugin.php | 28 +-- {assets => src}/js/elementor-mask.js | 8 +- webpack.config.js | 281 +++------------------- 5 files changed, 68 insertions(+), 280 deletions(-) create mode 100644 assets/js/elementor-mask.min.js rename {assets => src}/js/elementor-mask.js (91%) diff --git a/assets/js/elementor-mask.min.js b/assets/js/elementor-mask.min.js new file mode 100644 index 0000000..526624d --- /dev/null +++ b/assets/js/elementor-mask.min.js @@ -0,0 +1 @@ +(()=>{var e,a;e=jQuery,a={"ev-tel":"0000-0000","ev-tel-ddd":"(00) 0000-0000","ev-tel-ddd9":"(00) 00000-0000","ev-tel-us":"(000) 000-0000","ev-cpf":"000.000.000-00","ev-cnpj":"00.000.000/0000-00","ev-money":"000.000.000.000.000,00","ev-ccard":"0000-0000-0000-0000","ev-ccard-valid":"00/00","ev-cep":"00000-000","ev-time":"00:00:00","ev-date":"00/00/0000","ev-date_time":"00/00/0000 00:00:00"},e(window).on("load",(function(){"use strict";e(".fme-mask-input").each((function(){if(void 0!==e(this).data("fme-mask")){var t=e(this).data("fme-mask");"ev-cpf"==t||"ev-cnpj"==t||"ev-money"==t?e(this).mask(a[t],{reverse:!0}):e(this).mask(a[t])}})),jQuery(document).on("elementor/popup/show",(()=>{e(".fme-mask-input").each((function(){if(void 0!==e(this).data("fme-mask")){var t=e(this).data("fme-mask");"ev-cpf"==t||"ev-cnpj"==t||"ev-money"==t?e(this).mask(a[t],{reverse:!0}):e(this).mask(a[t])}}))}))}))})(); \ No newline at end of file diff --git a/includes/class-elementor-mask-control.php b/includes/class-elementor-mask-control.php index 0e5c237..1663b9e 100644 --- a/includes/class-elementor-mask-control.php +++ b/includes/class-elementor-mask-control.php @@ -7,7 +7,7 @@ use \Elementor\Repeater as ElementorRepeater; if ( ! defined( 'ABSPATH' ) ) { - exit; // Exit if accessed directly + exit; } class FME_Elementor_Forms_Mask { @@ -17,20 +17,18 @@ class FME_Elementor_Forms_Mask { ]; public function __construct() { - add_action( 'elementor/element/form/section_form_fields/before_section_end', [ $this, 'add_mask_control' ], 100, 2 ); add_filter( 'elementor_pro/forms/render/item', [ $this, 'add_mask_atributes' ], 10, 3 ); } /** * Add mask control - * + * * @since 1.0 * @param $element * @param $args */ public function add_mask_control( $element, $args ) { - $elementor = ElementorPlugin::instance(); $control_data = $elementor->controls_manager->get_control_from_stack( $element->get_name(), 'form_fields' ); @@ -74,17 +72,17 @@ public function add_mask_control( $element, $args ) { /** * Filter to pro version change control. - * + * * @since 1.5 */ $new_control = apply_filters( 'fme_after_mask_control_created', $new_control ); - + $mask_control = new ElementorRepeater(); $mask_control->add_control( 'fme_mask_control', $new_control ); /** * Action to insert more controls. - * + * * @since 1.5.2 */ do_action( 'fme_after_mask_control_added', $mask_control ); @@ -93,11 +91,11 @@ public function add_mask_control( $element, $args ) { /** * Register control in form advanced tab. - * + * * @since 1.5.2 */ $this->register_control_in_form_advanced_tab( $element, $control_data, $pattern_field ); - + } /** @@ -107,18 +105,17 @@ public function add_mask_control( $element, $args ) { * @param array $control_data * @param array $pattern_field * @return void - * + * * @since 1.5.2 */ public function register_control_in_form_advanced_tab( $element, $control_data, $pattern_field ) { - foreach( $pattern_field as $key => $control ) { - + if( $key !== '_id' ) { $new_order = []; foreach ( $control_data['fields'] as $field_key => $field ) { - + if ( 'field_value' === $field['name'] ) { $new_order[$key] = $control; } @@ -141,7 +138,6 @@ public function register_control_in_form_advanced_tab( $element, $control_data, * @return void */ public function add_mask_atributes( $field, $field_index, $form_widget ) { - if ( ! empty( $field['fme_mask_control'] ) && in_array( $field['field_type'], $this->allowed_fields ) && $field['fme_mask_control'] != 'sel' ) { $form_widget->add_render_attribute( 'input' . $field_index, 'data-fme-mask', $field['fme_mask_control'] ); @@ -150,13 +146,13 @@ public function add_mask_atributes( $field, $field_index, $form_widget ) { /** * After mask atribute added - * + * * Action fired to pro version add custom atributes. - * + * * @since 1.5.2 */ do_action( 'fme_aftere_mask_atribute_added', $field, $field_index, $form_widget ); return $field; } -} \ No newline at end of file +} diff --git a/includes/class-fme-plugin.php b/includes/class-fme-plugin.php index 8327dc0..a559f46 100644 --- a/includes/class-fme-plugin.php +++ b/includes/class-fme-plugin.php @@ -3,7 +3,7 @@ namespace FME\Includes; if ( ! defined( 'ABSPATH' ) ) { - exit; // Exit if accessed directly + exit; } /** @@ -14,7 +14,6 @@ * @since 1.4 */ final class FME_Plugin { - /** * Instance * @@ -76,7 +75,7 @@ public function __wakeup() { * Constructor * * Private method for prevent instance outsite the class. - * + * * @since 1.4 * * @access private @@ -97,9 +96,9 @@ private function __construct() { */ public function init() { - /** - * Check Elementor Por is actived - */ + /** + * Check Elementor Por is actived + */ if( ! $this->plugin_is_active( 'elementor-pro/elementor-pro.php' ) ) { add_action( 'admin_notices', [ $this, 'notice_elementor_pro_inactive' ] ); @@ -111,9 +110,9 @@ public function init() { // required files require_once FME_PLUGIN_PATH . '/includes/class-elementor-mask-control.php'; - - // instanciate mask control class - new FME_Elementor_Forms_Mask; + + // instanciate mask control class + new FME_Elementor_Forms_Mask; // register and enqueue scripts add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_plugin_js' ] ); @@ -129,15 +128,14 @@ public function init() { * @access public */ public function enqueue_plugin_js() { - wp_register_script( 'fme-jquery-mask', FME_PLUGN_URL . 'assets/lib/jquery.mask.js', array( 'jquery' ), FME_VERSION, true ); - wp_register_script( 'fme-mask', FME_PLUGN_URL . 'assets/js/elementor-mask.js', array( 'jquery' ), FME_VERSION, true ); + wp_register_script( 'fme-mask', FME_PLUGN_URL . 'assets/js/elementor-mask.min.js', array( 'jquery' ), FME_VERSION, true ); wp_enqueue_script( 'fme-jquery-mask' ); wp_enqueue_script( 'fme-mask' ); /** * Action for enqueue more scripts or remove current scripts - * + * * @since 1.5 */ do_action( 'fme_after_enqueue_scripts' ); @@ -161,12 +159,12 @@ public function notice_elementor_pro_inactive() { ); $html_message = sprintf( '

%1$s

', $message ); - echo wp_kses_post( $html_message ); + echo wp_kses_post( $html_message ); } /** * Check plugin is activated - * + * * @since 1.5 * @return boolean * @param string $plugin @@ -177,4 +175,4 @@ public function plugin_is_active( $plugin ) { } } -FME_Plugin::instance(); \ No newline at end of file +FME_Plugin::instance(); diff --git a/assets/js/elementor-mask.js b/src/js/elementor-mask.js similarity index 91% rename from assets/js/elementor-mask.js rename to src/js/elementor-mask.js index c2d2c66..8ad5096 100644 --- a/assets/js/elementor-mask.js +++ b/src/js/elementor-mask.js @@ -15,9 +15,9 @@ 'ev-date_time': '00/00/0000 00:00:00' }; - $(window).on( 'load', function() { + $(window).on( 'load', function() { "use strict"; - $('.fme-mask-input').each(function() { + $('.fme-mask-input').each(function() { if($( this ).data('fme-mask') !== undefined) { var inputMask = $( this ).data("fme-mask"); if(inputMask == 'ev-cpf' || inputMask == 'ev-cnpj' || inputMask == 'ev-money') { @@ -38,6 +38,6 @@ } } }); - }); + }); }); -})(jQuery); \ No newline at end of file +})(jQuery); diff --git a/webpack.config.js b/webpack.config.js index e405779..dae258b 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,244 +1,37 @@ -// const path = require('path'); -// const fs = require('fs'); -// const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); -// const MiniCssExtractPlugin = require("mini-css-extract-plugin"); - -// const orderJs = { -// mode: 'production', -// entry: './src/js/order/controller.js', -// output: { -// filename: 'order.min.js', -// path: path.resolve(__dirname, 'assets/js'), -// }, -// module: { -// rules: [ -// { -// test: /\.js$/, -// exclude: /node_modules/, -// use: { -// loader: 'esbuild-loader', -// options: { -// loader: 'js', -// target: 'es2016', -// }, -// }, -// }, -// ], -// }, -// }; - -// const srcJsAdminDirectory = path.resolve(__dirname, 'src/js/admin'); -// const adminEntries = fs.readdirSync(srcJsAdminDirectory).reduce((entries, file) => { -// if (file.endsWith('.js')) { -// const entryKey = file.replace('.js', ''); -// entries[entryKey] = path.resolve(srcJsAdminDirectory, file); -// } -// return entries; -// }, {}); - -// const adminJs = { -// mode: 'production', -// entry: adminEntries, -// output: { -// filename: '[name].min.js', -// path: path.resolve(__dirname, 'assets/js/admin'), -// }, -// module: { -// rules: [ -// { -// test: /\.js$/, -// exclude: /node_modules/, -// use: { -// loader: 'esbuild-loader', -// options: { -// loader: 'js', -// target: 'es2016', -// }, -// }, -// }, -// ], -// }, -// }; - -// const srcJsCustomFieldsDirectory = path.resolve(__dirname, 'src/js/admin/custom-fields'); -// const customFieldsEntries = fs.readdirSync(srcJsCustomFieldsDirectory).reduce((entries, file) => { -// if (file.endsWith('.js')) { -// const entryKey = file.replace('.js', ''); -// entries[entryKey] = path.resolve(srcJsCustomFieldsDirectory, file); -// } -// return entries; -// }, {}); - -// const customFieldsJs = { -// mode: 'production', -// entry: customFieldsEntries, -// output: { -// filename: '[name].min.js', -// path: path.resolve(__dirname, 'assets/js/admin/custom-fields'), -// }, -// module: { -// rules: [ -// { -// test: /\.js$/, -// exclude: /node_modules/, -// use: { -// loader: 'esbuild-loader', -// options: { -// loader: 'js', -// target: 'es2016', -// }, -// }, -// }, -// ], -// }, -// }; - -// const srcJsGeneralDirectory = path.resolve(__dirname, 'src/js/'); -// const generalEntries = fs.readdirSync(srcJsGeneralDirectory).reduce((entries, file) => { -// if (file.endsWith('.js')) { -// const entryKey = file.replace('.js', ''); -// entries[entryKey] = path.resolve(srcJsGeneralDirectory, file); -// } -// return entries; -// }, {}); - -// const generalJs = { -// mode: 'production', -// entry: generalEntries, -// output: { -// filename: '[name].min.js', -// path: path.resolve(__dirname, 'assets/js'), -// }, -// module: { -// rules: [ -// { -// test: /\.js$/, -// exclude: /node_modules/, -// use: { -// loader: 'esbuild-loader', -// options: { -// loader: 'js', -// target: 'es2016', -// }, -// }, -// }, -// ], -// }, -// }; - -// const srcJsOrdersPanelDirectory = path.resolve(__dirname, 'src/js/orders-panel'); -// const ordersPanelEntries = fs.readdirSync(srcJsOrdersPanelDirectory).map((file) => { -// if (file.endsWith('.js')) { -// return path.resolve(srcJsOrdersPanelDirectory, file); -// } -// }, []); - -// const ordersPanelJs = { -// mode: 'production', -// entry: ordersPanelEntries, -// output: { -// filename: 'frontend.min.js', -// path: path.resolve(__dirname, 'assets/js/orders-panel'), -// }, -// module: { -// rules: [ -// { -// test: /\.js$/, -// exclude: /node_modules/, -// use: { -// loader: 'esbuild-loader', -// options: { -// loader: 'js', -// target: 'es2016', -// }, -// }, -// }, -// ], -// }, -// }; - -// const deliveryPageCSS = { -// mode: 'production', -// entry: './src/css/delivery-page/style.css', -// output: { -// filename: 'style.bundle.js', -// path: path.resolve(__dirname, 'assets/css/'), -// }, -// module: { -// rules: [ -// { -// test: /\.css$/, -// use: [MiniCssExtractPlugin.loader, 'css-loader'], -// }, -// ], -// }, -// optimization: { -// minimizer: [new CssMinimizerPlugin()], -// }, -// plugins: [ -// new MiniCssExtractPlugin({ -// filename: 'delivery-frontend.min.css', -// }), -// ], -// }; - -// const orderPanelPageCSS = { -// mode: 'production', -// entry: './src/css/order-panel/style.css', -// output: { -// filename: 'style.bundle.js', -// path: path.resolve(__dirname, 'assets/css/'), -// }, -// module: { -// rules: [ -// { -// test: /\.css$/, -// use: [MiniCssExtractPlugin.loader, 'css-loader'], -// }, -// ], -// }, -// optimization: { -// minimizer: [new CssMinimizerPlugin()], -// }, -// plugins: [ -// new MiniCssExtractPlugin({ -// filename: 'order-panel-frontend.min.css', -// }), -// ], -// }; - -// const trackOrderPageCSS = { -// mode: 'production', -// entry: './src/css/track-order/style.css', -// output: { -// filename: 'style.bundle.js', -// path: path.resolve(__dirname, 'assets/css/'), -// }, -// module: { -// rules: [ -// { -// test: /\.css$/, -// use: [MiniCssExtractPlugin.loader, 'css-loader'], -// }, -// ], -// }, -// optimization: { -// minimizer: [new CssMinimizerPlugin()], -// }, -// plugins: [ -// new MiniCssExtractPlugin({ -// filename: 'track-order-frontend.min.css', -// }), -// ], -// }; - -// module.exports = [ -// orderJs, -// adminJs, -// customFieldsJs, -// generalJs, -// ordersPanelJs, -// deliveryPageCSS, -// orderPanelPageCSS, -// trackOrderPageCSS, -// ]; +const path = require('path'); +const fs = require('fs'); + +const srcJsGeneralDirectory = path.resolve(__dirname, 'src/js/'); +const generalEntries = fs.readdirSync(srcJsGeneralDirectory).reduce((entries, file) => { + if (file.endsWith('.js')) { + const entryKey = file.replace('.js', ''); + entries[entryKey] = path.resolve(srcJsGeneralDirectory, file); + } + return entries; + }, {}); + +const generalJs = { + mode: 'production', + entry: generalEntries, + output: { + filename: '[name].min.js', + path: path.resolve(__dirname, 'assets/js'), + }, + module: { + rules: [ + { + test: /\.js$/, + exclude: /node_modules/, + use: { + loader: 'esbuild-loader', + options: { + loader: 'js', + target: 'es2016', + }, + }, + }, + ], + }, +}; + +module.exports = [generalJs]; From 948d2ac876e14c26409b6e863c7a95c07577cf81 Mon Sep 17 00:00:00 2001 From: Eduardo Date: Tue, 7 Jan 2025 01:59:47 -0300 Subject: [PATCH 04/11] chore: set wpcs + update dependencies --- composer.json | 9 +++++++-- form-masks-for-elementor.php | 6 +++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index 698a8df..b35fdfc 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,12 @@ ], "minimum-stability": "stable", "require-dev": { - "squizlabs/php_codesniffer": "^3.6", - "wp-coding-standards/wpcs": "^2.3" + "squizlabs/php_codesniffer": "3.*", + "wp-coding-standards/wpcs": "3.*" + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } } } diff --git a/form-masks-for-elementor.php b/form-masks-for-elementor.php index 2c86975..73d4334 100644 --- a/form-masks-for-elementor.php +++ b/form-masks-for-elementor.php @@ -34,7 +34,7 @@ define( 'FME_PLUGIN_PATH', plugin_dir_path( __FILE__ ) ); define( 'FME_PLUGN_URL', plugin_dir_url( __FILE__ ) ); -define( 'FME_VERSION' , '2.0' ); +define( 'FME_VERSION', '2.0' ); define( 'FME_PHP_MINIMUM_VERSION', '7.4' ); define( 'FME_WP_MINIMUM_VERSION', '5.5' ); @@ -43,10 +43,10 @@ * * @since 1.6 */ -if( ! version_compare( PHP_VERSION, FME_PHP_MINIMUM_VERSION, '>=' ) ) { +if ( ! version_compare( PHP_VERSION, FME_PHP_MINIMUM_VERSION, '>=' ) ) { add_action( 'admin_notices', 'fme_admin_notice_php_version_fail' ); -} elseif( ! version_compare( get_bloginfo( 'version' ), FME_WP_MINIMUM_VERSION, '>=' ) ) { +} elseif ( ! version_compare( get_bloginfo( 'version' ), FME_WP_MINIMUM_VERSION, '>=' ) ) { add_action( 'admin_notices', 'fme_admin_notice_wp_version_fail' ); } else { From 99fb9057d4da67be8207c20dece2a6fc7cd9000b Mon Sep 17 00:00:00 2001 From: Eduardo Date: Thu, 9 Jan 2025 12:07:57 -0300 Subject: [PATCH 05/11] feat: v1 of input mask lib --- assets/js/input-mask.min.js | 1 + src/js/input-mask.js | 207 ++++++++++++++++++++++++++++++++++++ 2 files changed, 208 insertions(+) create mode 100644 assets/js/input-mask.min.js create mode 100644 src/js/input-mask.js diff --git a/assets/js/input-mask.min.js b/assets/js/input-mask.min.js new file mode 100644 index 0000000..33d48a1 --- /dev/null +++ b/assets/js/input-mask.min.js @@ -0,0 +1 @@ +new class{constructor(e){this.inputs=null,this.init(),this.mappedMasks=e||null,this.tokens={"#":{validateRule:/\d/,inputMode:"numeric"},"*":{validateRule:/[a-zA-Z]/,inputMode:"alpha"}}}init(){"complete"===document.readyState?(this.initModalListener(),this.getInput()):window.addEventListener("load",this.init.bind(this))}initModalListener(){const e=document.body;new MutationObserver((e=>{e.forEach((e=>{"childList"===e.type&&e.addedNodes.forEach((e=>{e.classList&&e.classList.contains("elementor-popup-modal")&&this.getInput()}))}))})).observe(e,{childList:!0})}getInput(){this.inputs=document.querySelectorAll("input[data-mask]"),this.inputs.forEach((e=>{this.handleMappedMasks(e),e.addEventListener("input",this.maskInput.bind(this)),e.addEventListener("keydown",this.handleBackspace.bind(this))}))}handleMappedMasks(e){if(!this.mappedMasks)return;const s=this.mappedMasks[e.dataset.mask];s&&(e.dataset.mask=s.mask,e.dataset.maskReverse=s.reverse)}maskInput(e){const s=e.target,t=s.dataset.mask,a=s.value,i=this.removeMask(t,a),r="true"===s.dataset.maskReverse,n=this.applyMask(i,t,r);s.value=n}removeMask(e,s){if(!e||!s)return s;const t=Object.keys(this.tokens),a=new RegExp(`[${t.join("")}]`,"g"),i=e.replace(a,"");return s.replace(new RegExp(`[${i}]`,"g"),"")}handleBackspace(e){const s=e.target;if("Backspace"===e.key&&s.selectionStart===s.selectionEnd){const t=s.selectionStart;if(t>0){const a=s.value;/\d/.test(a[t-1])||(e.preventDefault(),s.value=a.slice(0,t-1)+a.slice(t),s.setSelectionRange(t-1,t-1))}}}applyMask(e,s,t){if(!e)return e;let a="",i=0,r=s.split("");t&&(e=e.split("").reverse().join(""),r=r.reverse());for(let s=0;s { + mutations.forEach((mutation) => { + if (mutation.type === 'childList') { + mutation.addedNodes.forEach((node) => { + if ( + node.classList && + node.classList.contains('elementor-popup-modal') + ) { + this.getInput(); + } + }); + } + }); + }); + + observer.observe(body, { childList: true }); + } + + getInput() { + this.inputs = document.querySelectorAll('input[data-mask]'); + this.inputs.forEach((input) => { + this.handleMappedMasks(input); + input.addEventListener('input', this.maskInput.bind(this)); + input.addEventListener('keydown', this.handleBackspace.bind(this)); + }); + } + + handleMappedMasks(input) { + if (!this.mappedMasks) { + return; + } + + const replaceMaks = this.mappedMasks[input.dataset.mask]; + if (!replaceMaks) { + return; + } + + input.dataset.mask = replaceMaks.mask; + input.dataset.maskReverse = replaceMaks.reverse; + } + + maskInput(event) { + const input = event.target; + const mask = input.dataset.mask; + const value = input.value; + const unmaskedValue = this.removeMask(mask, value); + const isReverse = input.dataset.maskReverse === 'true'; + const maskedValue = this.applyMask(unmaskedValue, mask, isReverse); + + input.value = maskedValue; + } + + removeMask(mask, value) { + if (!mask || !value) { + return value; + } + + const allowTokens = Object.keys(this.tokens); + const allowTokensRegex = new RegExp(`[${allowTokens.join('')}]`, 'g'); + const maskLiteralsToRemove = mask.replace(allowTokensRegex, ''); + return value.replace(new RegExp(`[${maskLiteralsToRemove}]`, 'g'), ''); + } + + handleBackspace(event) { + const input = event.target; + if ( + event.key === 'Backspace' && + input.selectionStart === input.selectionEnd + ) { + const pos = input.selectionStart; + if (pos > 0) { + const value = input.value; + if (!/\d/.test(value[pos - 1])) { + event.preventDefault(); + input.value = value.slice(0, pos - 1) + value.slice(pos); + input.setSelectionRange(pos - 1, pos - 1); + } + } + } + } + + applyMask(unmaskedValue, mask, isReverse) { + if (!unmaskedValue) { + return unmaskedValue; + } + + let maskedValue = ''; + let valueIndex = 0; + let maskChars = mask.split(''); + + if (isReverse) { + unmaskedValue = unmaskedValue.split('').reverse().join(''); + maskChars = maskChars.reverse(); + } + + for (let i = 0; i < maskChars.length; i++) { + if (maskChars[i] === '#') { + if ( + new RegExp(this.tokens['#'].validateRule).test( + unmaskedValue[valueIndex] + ) + ) { + maskedValue += unmaskedValue[valueIndex]; + valueIndex++; + } else { + break; + } + } else { + maskedValue += maskChars[i]; + } + } + + if (isReverse) { + maskedValue = maskedValue.split('').reverse().join(''); + maskedValue = maskedValue.startsWith('.') + ? maskedValue.substring(1) + : maskedValue; + } + + return maskedValue; + } +} + +new inputMask({ + 'ev-tel': { + mask: '####-####', + reverse: false, + }, + 'ev-tel-ddd': { + mask: '(##) ####-####', + reverse: false, + }, + 'ev-tel-ddd9': { + mask: '(##) #####-####', + reverse: false, + }, + 'ev-tel-us': { + mask: '(###) ###-####', + reverse: false, + }, + 'ev-cpf': { + mask: '###.###.###-##', + reverse: false, + }, + 'ev-cnpj': { + mask: '##.###.###/####-##', + reverse: false, + }, + 'ev-money': { + mask: '###.###.###.###.###,##', + reverse: true, + }, + 'ev-ccard': { + mask: '####-####-####-####', + reverse: false, + }, + 'ev-ccard-valid': { + mask: '##/##', + reverse: false, + }, + 'ev-cep': { + mask: '#####-###', + reverse: false, + }, + 'ev-time': { + mask: '##:##:##', + reverse: false, + }, + 'ev-date': { + mask: '##/##/####', + reverse: false, + }, + 'ev-date_time': { + mask: '##/##/#### ##:##:##', + reverse: false, + }, +}); From d5f94d8b3d28f27b1fa4321b29824de57b853230 Mon Sep 17 00:00:00 2001 From: Eduardo Date: Thu, 9 Jan 2025 12:08:28 -0300 Subject: [PATCH 06/11] chore: remove old assets --- assets/js/elementor-mask.min.js | 1 - assets/lib/jquery.mask.js | 19 --------------- src/js/elementor-mask.js | 43 --------------------------------- 3 files changed, 63 deletions(-) delete mode 100644 assets/js/elementor-mask.min.js delete mode 100644 assets/lib/jquery.mask.js delete mode 100644 src/js/elementor-mask.js diff --git a/assets/js/elementor-mask.min.js b/assets/js/elementor-mask.min.js deleted file mode 100644 index 526624d..0000000 --- a/assets/js/elementor-mask.min.js +++ /dev/null @@ -1 +0,0 @@ -(()=>{var e,a;e=jQuery,a={"ev-tel":"0000-0000","ev-tel-ddd":"(00) 0000-0000","ev-tel-ddd9":"(00) 00000-0000","ev-tel-us":"(000) 000-0000","ev-cpf":"000.000.000-00","ev-cnpj":"00.000.000/0000-00","ev-money":"000.000.000.000.000,00","ev-ccard":"0000-0000-0000-0000","ev-ccard-valid":"00/00","ev-cep":"00000-000","ev-time":"00:00:00","ev-date":"00/00/0000","ev-date_time":"00/00/0000 00:00:00"},e(window).on("load",(function(){"use strict";e(".fme-mask-input").each((function(){if(void 0!==e(this).data("fme-mask")){var t=e(this).data("fme-mask");"ev-cpf"==t||"ev-cnpj"==t||"ev-money"==t?e(this).mask(a[t],{reverse:!0}):e(this).mask(a[t])}})),jQuery(document).on("elementor/popup/show",(()=>{e(".fme-mask-input").each((function(){if(void 0!==e(this).data("fme-mask")){var t=e(this).data("fme-mask");"ev-cpf"==t||"ev-cnpj"==t||"ev-money"==t?e(this).mask(a[t],{reverse:!0}):e(this).mask(a[t])}}))}))}))})(); \ No newline at end of file diff --git a/assets/lib/jquery.mask.js b/assets/lib/jquery.mask.js deleted file mode 100644 index 9098ddc..0000000 --- a/assets/lib/jquery.mask.js +++ /dev/null @@ -1,19 +0,0 @@ -// jQuery Mask Plugin v1.14.16 -// github.com/igorescobar/jQuery-Mask-Plugin -var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.findInternal=function(a,n,f){a instanceof String&&(a=String(a));for(var p=a.length,k=0;kg?h=10*d:e>=h&&e!==g?c.maskDigitPosMapOld[h]||(e=h,h=h-(k-l)-a,c.maskDigitPosMap[h]&&(h=e)):h>e&&(h=h+(l-k)+f)}return h},behaviour:function(d){d= -d||window.event;c.invalid=[];var e=b.data("mask-keycode");if(-1===a.inArray(e,l.byPassKeys)){e=c.getMasked();var h=c.getCaret(),g=b.data("mask-previus-value")||"";setTimeout(function(){c.setCaret(c.calculateCaretPosition(g))},a.jMaskGlobals.keyStrokeCompensation);c.val(e);c.setCaret(h);return c.callbacks(d)}},getMasked:function(a,b){var h=[],f=void 0===b?c.val():b+"",g=0,k=d.length,n=0,p=f.length,m=1,r="push",u=-1,w=0;b=[];if(e.reverse){r="unshift";m=-1;var x=0;g=k-1;n=p-1;var A=function(){return-1< -g&&-1 { - $('.fme-mask-input').each(function() { - if($( this ).data("fme-mask") !== undefined) { - var inputMask = $( this ).data("fme-mask"); - if(inputMask == 'ev-cpf' || inputMask == 'ev-cnpj' || inputMask == 'ev-money') { - $( this ).mask( fmeMasks[inputMask], {reverse: true} ); - } else { - $( this ).mask( fmeMasks[inputMask] ); - } - } - }); - }); - }); -})(jQuery); From d84694bf46fbbf021f7daffc35e1138f16953221 Mon Sep 17 00:00:00 2001 From: Eduardo Date: Thu, 9 Jan 2025 12:09:35 -0300 Subject: [PATCH 07/11] chore: enqueue new input mask lib + small code standards changes --- includes/class-elementor-mask-control.php | 5 ++--- includes/class-fme-plugin.php | 8 +++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/includes/class-elementor-mask-control.php b/includes/class-elementor-mask-control.php index 1663b9e..8f99126 100644 --- a/includes/class-elementor-mask-control.php +++ b/includes/class-elementor-mask-control.php @@ -13,7 +13,7 @@ class FME_Elementor_Forms_Mask { public $allowed_fields = [ - 'text' + 'text', ]; public function __construct() { @@ -139,8 +139,7 @@ public function register_control_in_form_advanced_tab( $element, $control_data, */ public function add_mask_atributes( $field, $field_index, $form_widget ) { if ( ! empty( $field['fme_mask_control'] ) && in_array( $field['field_type'], $this->allowed_fields ) && $field['fme_mask_control'] != 'sel' ) { - - $form_widget->add_render_attribute( 'input' . $field_index, 'data-fme-mask', $field['fme_mask_control'] ); + $form_widget->add_render_attribute( 'input' . $field_index, 'data-mask', $field['fme_mask_control'] ); $form_widget->add_render_attribute( 'input' . $field_index, 'class', 'fme-mask-input' ); } diff --git a/includes/class-fme-plugin.php b/includes/class-fme-plugin.php index a559f46..9b63aec 100644 --- a/includes/class-fme-plugin.php +++ b/includes/class-fme-plugin.php @@ -128,17 +128,15 @@ public function init() { * @access public */ public function enqueue_plugin_js() { - wp_register_script( 'fme-jquery-mask', FME_PLUGN_URL . 'assets/lib/jquery.mask.js', array( 'jquery' ), FME_VERSION, true ); - wp_register_script( 'fme-mask', FME_PLUGN_URL . 'assets/js/elementor-mask.min.js', array( 'jquery' ), FME_VERSION, true ); - wp_enqueue_script( 'fme-jquery-mask' ); - wp_enqueue_script( 'fme-mask' ); + \wp_register_script( 'fme-input-mask', FME_PLUGN_URL . 'assets/js/input-mask.min.js', array(), FME_VERSION, true ); + \wp_enqueue_script( 'fme-input-mask' ); /** * Action for enqueue more scripts or remove current scripts * * @since 1.5 */ - do_action( 'fme_after_enqueue_scripts' ); + \do_action( 'fme_after_enqueue_scripts' ); } /** From 0d42cf6946db641ef6fab6caadc28c97eef6c97b Mon Sep 17 00:00:00 2001 From: Eduardo Date: Thu, 9 Jan 2025 13:37:43 -0300 Subject: [PATCH 08/11] chore: add input mode --- assets/js/input-mask.min.js | 2 +- src/js/input-mask.js | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/assets/js/input-mask.min.js b/assets/js/input-mask.min.js index 33d48a1..4a34d74 100644 --- a/assets/js/input-mask.min.js +++ b/assets/js/input-mask.min.js @@ -1 +1 @@ -new class{constructor(e){this.inputs=null,this.init(),this.mappedMasks=e||null,this.tokens={"#":{validateRule:/\d/,inputMode:"numeric"},"*":{validateRule:/[a-zA-Z]/,inputMode:"alpha"}}}init(){"complete"===document.readyState?(this.initModalListener(),this.getInput()):window.addEventListener("load",this.init.bind(this))}initModalListener(){const e=document.body;new MutationObserver((e=>{e.forEach((e=>{"childList"===e.type&&e.addedNodes.forEach((e=>{e.classList&&e.classList.contains("elementor-popup-modal")&&this.getInput()}))}))})).observe(e,{childList:!0})}getInput(){this.inputs=document.querySelectorAll("input[data-mask]"),this.inputs.forEach((e=>{this.handleMappedMasks(e),e.addEventListener("input",this.maskInput.bind(this)),e.addEventListener("keydown",this.handleBackspace.bind(this))}))}handleMappedMasks(e){if(!this.mappedMasks)return;const s=this.mappedMasks[e.dataset.mask];s&&(e.dataset.mask=s.mask,e.dataset.maskReverse=s.reverse)}maskInput(e){const s=e.target,t=s.dataset.mask,a=s.value,i=this.removeMask(t,a),r="true"===s.dataset.maskReverse,n=this.applyMask(i,t,r);s.value=n}removeMask(e,s){if(!e||!s)return s;const t=Object.keys(this.tokens),a=new RegExp(`[${t.join("")}]`,"g"),i=e.replace(a,"");return s.replace(new RegExp(`[${i}]`,"g"),"")}handleBackspace(e){const s=e.target;if("Backspace"===e.key&&s.selectionStart===s.selectionEnd){const t=s.selectionStart;if(t>0){const a=s.value;/\d/.test(a[t-1])||(e.preventDefault(),s.value=a.slice(0,t-1)+a.slice(t),s.setSelectionRange(t-1,t-1))}}}applyMask(e,s,t){if(!e)return e;let a="",i=0,r=s.split("");t&&(e=e.split("").reverse().join(""),r=r.reverse());for(let s=0;s{e.forEach((e=>{"childList"===e.type&&e.addedNodes.forEach((e=>{e.classList&&e.classList.contains("elementor-popup-modal")&&this.getInput()}))}))})).observe(e,{childList:!0})}getInput(){this.inputs=document.querySelectorAll("input[data-mask]"),this.inputs.forEach((e=>{this.handleMappedMasks(e),e.addEventListener("input",this.maskInput.bind(this)),e.addEventListener("keydown",this.handleBackspace.bind(this))}))}handleMappedMasks(e){if(!this.mappedMasks)return;const t=this.mappedMasks[e.dataset.mask];t&&(e.dataset.mask=t.mask,e.dataset.maskReverse=t.reverse,e.inputmode=t.inputmode)}maskInput(e){const t=e.target,s=t.dataset.mask,a=t.value,i=this.removeMask(s,a),n="true"===t.dataset.maskReverse,r=this.applyMask(i,s,n);t.value=r}removeMask(e,t){if(!e||!t)return t;const s=Object.keys(this.tokens),a=new RegExp(`[${s.join("")}]`,"g"),i=e.replace(a,"");return t.replace(new RegExp(`[${i}]`,"g"),"")}handleBackspace(e){const t=e.target;if("Backspace"===e.key&&t.selectionStart===t.selectionEnd){const s=t.selectionStart;if(s>0){const a=t.value;/\d/.test(a[s-1])||(e.preventDefault(),t.value=a.slice(0,s-1)+a.slice(s),t.setSelectionRange(s-1,s-1))}}}applyMask(e,t,s){if(!e)return e;let a="",i=0,n=t.split("");s&&(e=e.split("").reverse().join(""),n=n.reverse());for(let t=0;t Date: Thu, 9 Jan 2025 18:22:35 -0300 Subject: [PATCH 09/11] chore: update readme --- readme.txt | 107 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 61 insertions(+), 46 deletions(-) diff --git a/readme.txt b/readme.txt index e843933..a7d4ebb 100644 --- a/readme.txt +++ b/readme.txt @@ -9,83 +9,98 @@ Requires PHP: 7.4 License: GPLv2License URI:https://www.gnu.org/licenses/gpl-2.0.html -Form Masks for Elementor add custom masks to fields in Elementor Pro Form. +Add custom masks to fields in Elementor Pro Forms with ease. Enhance your forms with flexible mask options and ensure better data input control. == Description == -#### => Now the plugin support masks on popups forms. #### +The Form Masks for Elementor plugin adds a custom control in the Advanced Tab of form fields, allowing you to easily apply input masks. This plugin requires Elementor Pro (Form Widget). -Form Masks for Elementor create a custom control in field advanced tab for your customize your fields with masks. This plugin require the Elementor Pro (Form Widget). - -The masks function with filed types 'text'. +Masks help users input structured data like phone numbers, dates, and more. +📽️ **Watch how it works:** https://www.youtube.com/watch?v=NYoykAUl4QE -#### Masks Available (FREE VERSION) #### - -* Phone - '0000-0000' or '(000) 000-0000' or '(00) 0000-0000' or '(00) 0.0000-0000' - -* CPF - '000.000.000-00' - -* CNPJ - '00.000.000/0000-00' - -* Date - '00/00/0000' - -* Time - '00:00:00' - -* Date and Time - '00/00/0000 00:00:00' - -* Money - '000.000.000.000.000,00' - -* CEP - '00000-000' - -* Credit Card - 0000-0000-0000-0000 - -* Credit Card Date - 00/00 - -#### PRO VERSION #### - -[Check the PRO version](https://codecanyon.net/item/form-masks-for-elementor/25872641) - -In PRO version you can WRITE YOUR CUSTOM MASKS. Create the mask you want for your inputs! - +**Features (FREE VERSION)** + +Ready-to-Use Masks +* **Phone**: + 0000-0000 + (000) 000-0000 + (00) 0000-0000 + (00) 0.0000-0000 +* **CPF (Brazilian ID)**: 000.000.000-00 +* **CNPJ (Brazilian Company ID)**: 00.000.000/0000-00 +* **Date**: 00/00/0000 +* **Time**: 00:00:00 +* **Date and Time**: 00/00/0000 00:00:00 +* **Money**: 000.000.000.000.000,00 +* **Postal Code (CEP)**: 00000-000 +* **Credit Card**: 0000-0000-0000-0000 +* **Credit Card Expiry Date**: 00/00 + +**Exclusive PRO Features** +* **Custom Masks**: Create your own masks for maximum flexibility. Tailor your forms to any requirement. + +🚀 **Coming Soon to the PRO Version** +* **Minimum character limits** to prevent incomplete submissions. +* **Prefix and suffix** options for masks. +* Built-in **validation for CPF, CNPJ**, and other formats. +* And much more… + +**PRO VERSION** +[Check the PRO version here](https://codecanyon.net/item/form-masks-for-elementor/25872641) + +📽️ **Watch how it works:** https://www.youtube.com/watch?v=XAuL43HFh8I -#### CREDITS #### +**Why Choose Form Masks for Elementor?** +* Simple to set up and use. +* Increases form usability and data accuracy. +* Seamless integration with Elementor Pro. +* Regular updates with new features and improvements. -This plugin use the jQuery Mask library plugin. [jQuery Mask Plugin](https://github.com/igorescobar/jQuery-Mask-Plugin) +== More Plugins by Us == -== More plugins? == +Discover other plugins to enhance your WordPress experience:: [WordPress Plugins](https://eduardovillao.me/wordpress-plugins/) -Check my other plugins: [WordPress Plugins](https://eduardovillao.me/wordpress-plugins/) +== Learn WordPress Tips == -== WordPress Tips? == - -Check my blog: [WordPress Tips](https://eduardovillao.me/blog/) +Visit our blog for expert WordPress insights: [WordPress Tips](https://eduardovillao.me/blog/) == Plugins Suggestions? == -Please, send to me: [plugins@eduardovillao.me](mailto:plugins@eduardovillao.me) +We’d love to hear from you! [plugins@eduardovillao.me](mailto:plugins@eduardovillao.me) == Installation == 1. Upload the plugin files to the WordPress - 2. Activate the plugin in WordPress - 3. Go to Widget Elementor Pro in your page - -4. Select the custom mask for field in advanced field tab - +4. Select the custom mask for field in advanced field tab **(works only on text field)** 5. Go to the page for see the results (outside the Elementor editor) == Frequently Asked Questions == += Does the plugin work without Elementor Pro? = + +No, the Form Masks for Elementor plugin requires Elementor Pro, as it relies on the Form Widget, which is only available in Elementor Pro. The plugin is not compatible with alternatives like Pro Elements or similar Elementor-like versions. + += Does the mask work on all field types? = + +The plugin supports masks only for fields of type text. This means that masks will not work on fields like textarea, number, or other custom field types. + += Can I create my own masks? = + +Yes, but this feature is available only in the PRO version. With the PRO version, you can define custom masks tailored to your specific needs. + == Screenshots == == Changelog == = 2.0 = +* New: add inputmode to open keybord with input context. Ex.: input with tel mask will open numeric keybord. +* New: remove jQuery mask library to use our own custom library. +* New: support to masks on popup improved. * Changed: minimum PHP version changed to 7.4. * Changed: improve build proccess to assets. From 65f13894648f7831ea6fe3438761091315a937f4 Mon Sep 17 00:00:00 2001 From: Eduardo Date: Thu, 9 Jan 2025 18:23:14 -0300 Subject: [PATCH 10/11] chore: change mask token to numbers --- assets/js/input-mask.min.js | 2 +- src/js/input-mask.js | 35 ++++++++++++++++------------------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/assets/js/input-mask.min.js b/assets/js/input-mask.min.js index 4a34d74..d4ce81d 100644 --- a/assets/js/input-mask.min.js +++ b/assets/js/input-mask.min.js @@ -1 +1 @@ -new class{constructor(e){this.inputs=null,this.init(),this.mappedMasks=e||null,this.tokens={"#":{validateRule:/\d/},"*":{validateRule:/[a-zA-Z]/}}}init(){"complete"===document.readyState?(this.initModalListener(),this.getInput()):window.addEventListener("load",this.init.bind(this))}initModalListener(){const e=document.body;new MutationObserver((e=>{e.forEach((e=>{"childList"===e.type&&e.addedNodes.forEach((e=>{e.classList&&e.classList.contains("elementor-popup-modal")&&this.getInput()}))}))})).observe(e,{childList:!0})}getInput(){this.inputs=document.querySelectorAll("input[data-mask]"),this.inputs.forEach((e=>{this.handleMappedMasks(e),e.addEventListener("input",this.maskInput.bind(this)),e.addEventListener("keydown",this.handleBackspace.bind(this))}))}handleMappedMasks(e){if(!this.mappedMasks)return;const t=this.mappedMasks[e.dataset.mask];t&&(e.dataset.mask=t.mask,e.dataset.maskReverse=t.reverse,e.inputmode=t.inputmode)}maskInput(e){const t=e.target,s=t.dataset.mask,a=t.value,i=this.removeMask(s,a),n="true"===t.dataset.maskReverse,r=this.applyMask(i,s,n);t.value=r}removeMask(e,t){if(!e||!t)return t;const s=Object.keys(this.tokens),a=new RegExp(`[${s.join("")}]`,"g"),i=e.replace(a,"");return t.replace(new RegExp(`[${i}]`,"g"),"")}handleBackspace(e){const t=e.target;if("Backspace"===e.key&&t.selectionStart===t.selectionEnd){const s=t.selectionStart;if(s>0){const a=t.value;/\d/.test(a[s-1])||(e.preventDefault(),t.value=a.slice(0,s-1)+a.slice(s),t.setSelectionRange(s-1,s-1))}}}applyMask(e,t,s){if(!e)return e;let a="",i=0,n=t.split("");s&&(e=e.split("").reverse().join(""),n=n.reverse());for(let t=0;t{e.forEach((e=>{"childList"===e.type&&e.addedNodes.forEach((e=>{e.classList&&e.classList.contains("elementor-popup-modal")&&this.getInput()}))}))})).observe(e,{childList:!0})}getInput(){this.inputs=document.querySelectorAll("input[data-mask]"),this.inputs.forEach((e=>{this.handleMappedMasks(e),e.addEventListener("input",this.maskInput.bind(this)),e.addEventListener("keydown",this.handleBackspace.bind(this))}))}handleMappedMasks(e){if(!this.mappedMasks)return;const t=this.mappedMasks[e.dataset.mask];t&&(e.dataset.mask=t.mask,e.dataset.maskReverse=t.reverse,e.inputmode=t.inputmode)}maskInput(e){const t=e.target,s=t.dataset.mask,i=t.value,a=this.removeMask(s,i),n="true"===t.dataset.maskReverse,r=this.applyMask(a,s,n);t.value=r}removeMask(e,t){if(!e||!t)return t;const s=Object.keys(this.tokens),i=new RegExp(`[${s.join("")}]`,"g"),a=e.replace(i,"");return t.replace(new RegExp(`[${a}]`,"g"),"")}handleBackspace(e){const t=e.target;if("Backspace"===e.key&&t.selectionStart===t.selectionEnd){const s=t.selectionStart;if(s>0){const i=t.value;/\d/.test(i[s-1])||(e.preventDefault(),t.value=i.slice(0,s-1)+i.slice(s),t.setSelectionRange(s-1,s-1))}}}applyMask(e,t,s){if(!e)return e;let i="",a=0,n=t.split("");s&&(e=e.split("").reverse().join(""),n=n.reverse());for(let t=0;t Date: Thu, 9 Jan 2025 18:27:50 -0300 Subject: [PATCH 11/11] chore: update github readme --- README.md | 147 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 132 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 67b8857..e6b48ce 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,150 @@ # Form Masks for Elementor -Form Masks for Elementor create a custom control in field advanced tab for your customize your fields with masks. This plugin require the Elementor Pro (Form Widget). +The Form Masks for Elementor plugin adds a custom control in the Advanced Tab of form fields, allowing you to easily apply input masks. This plugin requires Elementor Pro (Form Widget). -The masks work with filed types 'text'. +Masks help users input structured data like phone numbers, dates, and more. +📽️ **Watch how it works:** https://www.youtube.com/watch?v=NYoykAUl4QE -#### Masks Available #### +## Features (FREE VERSION) -* Phone - '0000-0000' or '(000) 000-0000' or '(00) 0000-0000' +Ready-to-Use Masks +- **Phone**: + - 0000-0000 + - (000) 000-0000 + - (00) 0000-0000 + - (00) 0.0000-0000 +- **CPF (Brazilian ID)**: 000.000.000-00 +- **CNPJ (Brazilian Company ID)**: 00.000.000/0000-00 +- **Date**: 00/00/0000 +- **Time**: 00:00:00 +- **Date and Time**: 00/00/0000 00:00:00 +- **Money**: 000.000.000.000.000,00 +- **Postal Code (CEP)**: 00000-000 +- **Credit Card**: 0000-0000-0000-0000 +- **Credit Card Expiry Date**: 00/00 -* CPF - '000.000.000-00' +## Exclusive PRO Features +- **Custom Masks**: Create your own masks for maximum flexibility. Tailor your forms to any requirement. -* CNPJ - '00.000.000/0000-00' +🚀 **Coming Soon to the PRO Version** +- **Minimum character limits** to prevent incomplete submissions. +- **Prefix and suffix** options for masks. +- Built-in **validation for CPF, CNPJ**, and other formats. +- And much more… -* Date - '00/00/0000' +**PRO VERSION** +[Check the PRO version here](https://codecanyon.net/item/form-masks-for-elementor/25872641) -* Time - '00:00:00' +📽️ **Watch how it works:** +https://www.youtube.com/watch?v=XAuL43HFh8I -* Date and Time - '00/00/0000 00:00:00' +## Why Choose Form Masks for Elementor? +- Simple to set up and use. +- Increases form usability and data accuracy. +- Seamless integration with Elementor Pro. +- Regular updates with new features and improvements. -* Money - '000.000.000.000.000,00' +## More Plugins by Us -* CEP - '00000-000' +Discover other plugins to enhance your WordPress experience:: [WordPress Plugins](https://eduardovillao.me/wordpress-plugins/) -#### Masks Available #### +## Learn WordPress Tips -Check the [Pro version](https://codecanyon.net/item/form-masks-for-elementor/25872641) +Visit our blog for expert WordPress insights: [WordPress Tips](https://eduardovillao.me/blog/) -#### CREDITS #### +## Plugins Suggestions? -This plugin use the jQuery Mask library plugin. [jQuery Mask Plugin](https://github.com/igorescobar/jQuery-Mask-Plugin) +We’d love to hear from you! [plugins@eduardovillao.me](mailto:plugins@eduardovillao.me) + +## Installation + +1. Upload the plugin files to the WordPress +2. Activate the plugin in WordPress +3. Go to Widget Elementor Pro in your page +4. Select the custom mask for field in advanced field tab **(works only on text field)** +5. Go to the page for see the results (outside the Elementor editor) + +## Frequently Asked Questions + +1. Does the plugin work without Elementor Pro? + +No, the Form Masks for Elementor plugin requires Elementor Pro, as it relies on the Form Widget, which is only available in Elementor Pro. The plugin is not compatible with alternatives like Pro Elements or similar Elementor-like versions. + +2. Does the mask work on all field types? + +The plugin supports masks only for fields of type text. This means that masks will not work on fields like textarea, number, or other custom field types. + +3. Can I create my own masks? + +Yes, but this feature is available only in the PRO version. With the PRO version, you can define custom masks tailored to your specific needs. + +## Changelog +``` += 2.0 = +* New: add inputmode to open keybord with input context. Ex.: input with tel mask will open numeric keybord. +* New: remove jQuery mask library to use our own custom library. +* New: support to masks on popup improved. +* Changed: minimum PHP version changed to 7.4. +* Changed: improve build proccess to assets. + += 1.6.5 = +* Changed: compatibility with WordPress 6.7. +* Changed: code improvements. + += 1.6.4 = +* Changed: compatibility with WordPress 6.5. +* Changed: code improvements. + += 1.6.3 = +* Changed: compatibility with WordPress 6.2. + += 1.6.2 = +* Changed: compatibility with WordPress 6.1. + += 1.6.1 = +* Changed: compatibility with WordPress 6.0. + += 1.6 = +* Changed: support to string translations. +* Changed: code improvements. +* Changed: plugin header requirements improved. + += 1.5.3 = +* Tweak: conflict with jQuery old versions. + += 1.5.2 = +* Tweak: add hooks to pro version new features. +* Tweak: code improvements. + += 1.5.1 = +* Tweak: mask with 9 digits improved. +* Tweak: update and minify jQuery mask lib. + += 1.5 = +* New: support for Pro version. +* Tweak: improve JS mask files. +* Tweak: improve plugin code structure. + += 1.4.2 = +* Suppor to WordPress 5.8. + += 1.4.1 = +* Fix: active mask on popup is called by link, button and others. + += 1.4 = +* Support for Elementor Popup. + += 1.3 = +* Add new mask - Credit card and Credit card date. + += 1.2 = +* Add new mask - Phone 9 digits. + += 1.1 = +* Update the mask control. + += 1.0 = +* Initial release. +```