PluginProbe
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder / 2.21.4
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder v2.21.4
V-3.3.0 3.2.2 3.2.1 3.2.0 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 V3.0.3 V3.0.2 -3.0.1 V_3.0.0 1.1.1 1.1.8 1.2 1.3 1.4 1.4.18 1.5.2 1.9 2.0 2.10.0 2.10.1 2.10.2 All 137 releases
← All changes | includes/Admin/Form/FrontEndScriptGenerator.php +381 -174 2.02.21.4 View file →
@@ -1,15 +1,25 @@
1 1 <?php
2 2
3 3 namespace BitCode\BitForm\Admin\Form;
4 4
5 +use BitCode\BitForm\Admin\Form\InitJs\HCaptcha;
6 +use BitCode\BitForm\Admin\Form\InitJs\Paypal;
7 +use BitCode\BitForm\Admin\Form\InitJs\Razorpay;
8 +use BitCode\BitForm\Admin\Form\InitJs\Recaptcha;
5 9 use BitCode\BitForm\Admin\Form\InitJs\RecaptchaV3;
6 -use BitCode\BitForm\Core\Form\FormManager;
7 -use BitCode\BitForm\Core\Integration\IntegrationHandler;
10 +use BitCode\BitForm\Admin\Form\InitJs\ScriptLoader;
11 +use BitCode\BitForm\Admin\Form\InitJs\Stripe;
12 +use BitCode\BitForm\Admin\Form\InitJs\Turnstile;
13 +use BitCode\BitForm\Core\Util\FileHandler;
8 14 use BitCode\BitForm\Core\Util\Log;
15 +use BitCode\BitForm\Core\Util\Utilities;
16 +use BitCode\BitForm\Core\WorkFlow\WorkFlowHandler;
17 +use BitCode\BitFormPro\Admin\FormSettings\FormAbandonment;
9 18 use WP_Error;
10 19
11 -class FrontEndScriptGenerator {
20 +class FrontEndScriptGenerator
21 +{
12 22 private $_scriptAddedFlags;
13 23 private $_fields;
14 24 private $_formContents;
15 25 private $_jsFilesNeeded;
@@ -15,23 +25,28 @@
15 25 private $_jsFilesNeeded;
16 26 private $_loadedScriptsList;
17 27 private $_validationJsFilesNeeded;
18 28
19 - public function __construct() {
29 + public function __construct()
30 + {
20 31 $this->_scriptAddedFlags = [];
21 32 $this->_fields = [];
22 33 $this->_jsFilesNeeded = [];
23 34 $this->_loadedScriptsList = [];
24 - $this->_validationJsFilesNeeded = ScriptFilePriorityManager::validationScriptFile();
35 + $this->_validationJsFilesNeeded = ScriptFilePriorityManager::validationAndOtherScriptFile();
25 36 }
26 37
27 - private static function generateBfGlobalObjJS($contentIds = []) {
28 - // ["bitforms_3_submit_85_1", "bitforms_3_submit_85_2"]
29 - // bf_globals.{contentId}.inits
30 - $contentidArray = json_encode($contentIds);
38 + private static function generateBfGlobalObjJS($contentIds = [])
39 + {
40 + $contentidArray = wp_json_encode($contentIds);
31 41 return <<<GLOBALOBJ
32 42 if(!window.bf_globals){ window.bf_globals = {};}
33 43 $contentidArray.forEach(function(contentId){
44 + const form = document.getElementById(contentId);
45 + if(!form){
46 + delete window.bf_globals[contentId];
47 + return;
48 + }
34 49 if(!window.bf_globals[contentId]){
35 50 window.bf_globals[contentId] = {inits: {}, contentId: contentId};
36 51 }else{
37 52 window.bf_globals[contentId].inits = {};
@@ -36,13 +51,15 @@
36 51 }else{
37 52 window.bf_globals[contentId].inits = {};
38 53 window.bf_globals[contentId].contentId = contentId;
39 54 }
55 +
40 56 });
41 57 GLOBALOBJ;
42 58 }
43 59
44 - private static function isValidationNeeded($fldData) {
60 + private static function isValidationNeeded($fldData)
61 + {
45 62 $validationsToCheck = ['valid->req', 'valid->regexr', 'mn', 'mx', 'opt', 'err->invalid->show'];
46 63 foreach ($validationsToCheck as $property) {
47 64 $needValidation = Helpers::property_exists_nested($fldData, $property);
48 65 if ($needValidation) {
@@ -51,9 +68,10 @@
51 68 }
52 69 return false;
53 70 }
54 71
55 - public function generateJsFile($formContents, $fields, $contentIds, $postId, $formIDs = null, $preview = false) {
72 + public function generateJsFile($formContents, $fields, $contentIds, $postId, $formIDs = null, $preview = 'classic')
73 + {
56 74 add_option('bitforms_frontend_js_generating', true);
57 75 $this->_formContents = $formContents;
58 76 $this->_fields = $fields;
59 77
@@ -59,11 +77,8 @@
59 77
60 78 $this->appendJs(self::generateBfGlobalObjJS($contentIds), $postId, $preview, 'w');
61 79 $this->_jsFilesNeeded = ScriptFilePriorityManager::jsFile();
62 80
63 - // Recaptcha v3 script is loaded separately
64 - $this->appendJs($this->getRecaptchaV3Script($formIDs), $postId, $preview);
65 -
66 81 // helper js files for whole form
67 82 foreach ($this->_jsFilesNeeded['helperScript'] as $jsFile) {
68 83 $this->addScriptInLoadedScriptsList($jsFile);
69 84 }
@@ -76,13 +91,28 @@
76 91
77 92 // for frontend helper js files
78 93 $this->jsFrontendScript();
79 94
80 - // for hidden Field when catch plugin on
95 + // for hidden Field when cache plugin on
81 96 $this->jsHiddenFieldScript();
82 97
98 + // for form abandonment scripts
99 + $this->jsFormAbandonmentScripts();
100 +
101 + // multi step form scripts
102 + $this->multiStepFormScripts();
103 +
104 + // conversational form scripts
105 + $this->conversationalFormScripts();
106 +
83 107 //⚠👆 every script file generate method call before this method
84 108 $this->appendJs($this->getScript(), $postId, $preview);
109 + $this->appendJs($this->generateFieldConfigsJs($contentIds), $postId, $preview);
110 + // init all js events and functions at last
111 + $this->appendJs(self::getFileFromAssetsJs('bitform-init.min.js'), $postId, $preview);
112 + if (defined('ELEMENTOR_PRO_VERSION')) {
113 + $this->appendJs(self::getFileFromAssetsJs('bitform-elementor.min.js'), $postId, $preview);
114 + }
85 115
86 116 // for js file minification
87 117 $this->appendJs(self::getCustomJsCodes($contentIds), $postId, $preview);
88 118 delete_option('bitforms_frontend_js_generating');
@@ -88,63 +118,93 @@
88 118 delete_option('bitforms_frontend_js_generating');
89 119 return true;
90 120 }
91 121
92 -/*
93 - public function generateJsFile($formContents, $fields, $contentIds, $postId, $formIDs = null, $preview = false) {
94 - $this->_formContents = $formContents;
95 - $this->_fields = $fields;
122 + private function multiStepFormScripts()
123 + {
124 + foreach ($this->_formContents as $formContent) {
125 + $layout = $formContent->layout;
126 + if (is_array($layout) && count($layout) > 1) {
127 + $files = ScriptFilePriorityManager::multiStepFiles();
128 + foreach ($files as $file) {
129 + $this->addScriptInLoadedScriptsList($file);
130 + }
131 + }
132 + }
133 + }
96 134
97 - $script = '';
98 - $script .= self::generateBfGlobalObjJS($contentIds);
99 - $this->_jsFilesNeeded = ScriptFilePriorityManager::jsFile();
135 + private function conversationalFormScripts()
136 + {
137 + foreach ($this->_formContents as $formContent) {
138 + if (!empty($formContent->formInfo->conversationalSettings) && $formContent->formInfo->conversationalSettings->enable) {
139 + $files = ScriptFilePriorityManager::conversationalFormFiles();
140 + foreach ($files as $file) {
141 + $this->addScriptInLoadedScriptsList($file);
142 + }
143 + }
144 + }
145 + }
100 146
101 - // Recaptcha v3 script is loaded separately
102 - $script .= $this->getRecaptchaV3Script($formIDs);
147 + private function jsFormAbandonmentScripts()
148 + {
149 + if (!Utilities::isPro() || !class_exists('\BitCode\BitFormPro\Admin\FormSettings\FormAbandonment')) {
150 + return;
151 + }
152 + // check if any of the form has form abandonment enabled
153 + $allFiles = [];
154 + foreach ($this->_formContents as $formContent) {
155 + $formAbandonmentSettings = FormAbandonment::getFormAbandonmentSettings($formContent->formId);
156 + if (!empty($formAbandonmentSettings->saveFormDraft)) {
157 + $neededFiles = ScriptFilePriorityManager::formAbandonmentNeededFiles('autoSave');
158 + $allFiles = array_merge($allFiles, $neededFiles);
159 + break;
160 + }
103 161
104 - // custom js files for whole form
105 - foreach ($this->_jsFilesNeeded['helperScript'] as $jsFile) {
162 + $workflowHandler = new WorkFlowHandler($formContent->formId);
163 + $allWorkflows = $workflowHandler->getAllworkFlow();
164 + foreach ($allWorkflows as $workflow) {
165 + foreach ($workflow['conditions'] as $cond) {
166 + if (!empty($cond->actions) && !empty($cond->actions->fields)) {
167 + foreach ($cond->actions->fields as $fldAction) {
168 + if (empty($fldAction->field) || empty($fldAction->action)) {
169 + continue;
170 + }
171 + if ('_bf_form' === $fldAction->field && 'save_draft' === $fldAction->action) {
172 + $neededFiles = ScriptFilePriorityManager::formAbandonmentNeededFiles();
173 + $allFiles = array_merge($allFiles, $neededFiles);
174 + }
175 + }
176 + }
177 + }
178 + }
179 + }
180 + if (isset($this->_fields['button'])) {
181 + foreach ($this->_fields['button'] as $button) {
182 + if ('save-draft' === $button['field']->btnTyp) {
183 + $neededFiles = ScriptFilePriorityManager::formAbandonmentNeededFiles();
184 + $allFiles = array_merge($allFiles, $neededFiles);
185 + break;
186 + }
187 + }
188 + }
189 + //
190 + if (empty($allFiles)) {
191 + return;
192 + }
193 + foreach ($allFiles as $jsFile) {
106 194 $this->addScriptInLoadedScriptsList($jsFile);
107 195 }
196 + }
108 197
109 - // for add validation js files
110 - $this->jsValidationNeededFile();
111 -
112 - // js files for all fields
113 - $this->jsFieldsNeededFile();
114 -
115 - // for frontend helper js files
116 - $this->jsFrontendScript();
117 -
118 - // for hidden Field when catch plugin on
119 - $this->jsHiddenFieldScript();
120 -
121 - //⚠👆 every script file generate method call before this method
122 - $script .= $this->getScript();
123 -
124 - // for js file minification
125 - $script = Helpers::minifyJS($script);
126 -
127 - $script .= self::getCustomJsCodes($contentIds);
128 -
129 - // write script file
198 + private function appendJs($script, $postId, $previewMode, $mode = 'a')
199 + {
130 200 $fileName = '';
131 201 $path = '';
132 - if ($preview) {
133 - $fileName = "preview-{$postId}.js";
202 +
203 + if ('conversational' === $previewMode) {
204 + $fileName = "bitform-conversational-{$postId}.js";
134 205 $path = 'form-scripts';
135 - } else {
136 - $fileName = "bitform-js-$postId.js";
137 - $path = "form-scripts/{$postId}";
138 - }
139 - Helpers::saveFile($path, $fileName, $script, 'w');
140 - return true;
141 - }
142 -*/
143 - private function appendJs($script, $postId, $preview, $mode = 'a') {
144 - $fileName = '';
145 - $path = '';
146 - if ($preview) {
206 + } elseif ('preview' === $previewMode) {
147 207 $fileName = "preview-{$postId}.js";
148 208 $path = 'form-scripts';
149 209 } else {
150 210 $fileName = "bitform-js-$postId.js";
@@ -149,28 +209,13 @@
149 209 } else {
150 210 $fileName = "bitform-js-$postId.js";
151 211 $path = "form-scripts/{$postId}";
152 212 }
153 - Helpers::saveFile($path, $fileName, Helpers::minifyJS($script), $mode);
213 + Helpers::saveFile($path, $fileName, Helpers::minifyJs($script), $mode);
154 214 }
155 215
156 - private function getRecaptchaV3Script($formIds) {
157 - foreach ($formIds as $formID) {
158 - if (in_array('RecaptchaV3', $this->_scriptAddedFlags)) {
159 - break;
160 - }
161 - $getCaptchaV3Settings = (new FormManager($formID))->getCaptchaV3Settings();
162 - if ($getCaptchaV3Settings) {
163 - $integrationHandler = new IntegrationHandler(0);
164 - $allFormIntegrations = $integrationHandler->getAllIntegration('app', 'gReCaptchaV3');
165 - $siteKey = json_decode($allFormIntegrations[0]->integration_details)->siteKey;
166 - $this->_scriptAddedFlags[] = 'RecaptchaV3';
167 - return RecaptchaV3::init($siteKey);
168 - }
169 - }
170 - }
171 -
172 - private function getScript() {
216 + private function getScript()
217 + {
173 218 usort($this->_loadedScriptsList, function ($a, $b) {
174 219 return $a['priority'] - $b['priority'];
175 220 });
176 221
@@ -183,17 +228,8 @@
183 228 continue;
184 229 }
185 230 continue;
186 231 }
187 - if ('init' === $scriptFileArr['scriptTyp']) {
188 - $fieldObjInstance = $scriptFileArr['source'] . $fileNam;
189 - if (!class_exists($fieldObjInstance)) {
190 - continue;
191 - } // when class not found, skip load script
192 - $encodedConf = json_encode($scriptFileArr['field']->fldConfigs);
193 - $script .= $fieldObjInstance::init($scriptFileArr['fk'], $encodedConf, $scriptFileArr['contentId']);
194 - continue;
195 - }
196 232 if ('custom' === $scriptFileArr['scriptTyp']) {
197 233 $fileInstance = $scriptFileArr['source'] . $fileNam;
198 234 if (!class_exists($fileInstance)) {
199 235 continue;
@@ -203,9 +239,10 @@
203 239 }
204 240 return $script;
205 241 }
206 242
207 - private function jsValidationNeededFile() {
243 + private function jsValidationNeededFile()
244 + {
208 245 foreach ($this->_fields as $flds) {
209 246 foreach ($flds as $fld) {
210 247 $fldData = $fld['field'];
211 248 // for validation js files
@@ -228,18 +265,30 @@
228 265
229 266 $validationScriptFileMapping = ScriptFilePriorityManager::validationScriptFileMapping($fldData->typ);
230 267 if ($validationScriptFileMapping) {
231 268 foreach ($validationScriptFileMapping as $key => $value) {
232 - foreach ($value['paths'] as $path) {
269 + $paths = $value['paths'] ?? [];
270 + $hasMatchingPath = false;
271 + foreach ($paths as $path) {
233 272 if (Helpers::property_exists_nested($fldData, $path)) {
234 - $file = $this->_validationJsFilesNeeded[$key];
235 - $this->addScriptInLoadedScriptsList($file);
273 + $hasMatchingPath = true;
274 + break; // one match is enough
236 275 }
237 276 }
238 - if (isset($value['dependencies'])) {
239 - foreach ($value['dependencies'] as $dependency) {
240 - $dependencyFile = $this->_validationJsFilesNeeded[$dependency];
241 - $this->addScriptInLoadedScriptsList($dependencyFile);
277 +
278 + if (!$hasMatchingPath) {
279 + continue;
280 + }
281 +
282 + // Add the main script once
283 + if (!empty($this->_validationJsFilesNeeded[$key])) {
284 + $this->addScriptInLoadedScriptsList($this->_validationJsFilesNeeded[$key]);
285 + }
286 +
287 + // Add dependencies once each
288 + foreach (($value['dependencies'] ?? []) as $dep) {
289 + if (!empty($this->_validationJsFilesNeeded[$dep])) {
290 + $this->addScriptInLoadedScriptsList($this->_validationJsFilesNeeded[$dep]);
242 291 }
243 292 }
244 293 }
245 294 }
@@ -246,9 +295,10 @@
246 295 }
247 296 }
248 297 }
249 298
250 - private function jsFieldsNeededFile() {
299 + private function jsFieldsNeededFile()
300 + {
251 301 foreach ($this->_fields as $typ => $flds) {
252 302 if (!array_key_exists($typ, $this->_jsFilesNeeded)) {
253 303 continue;
254 304 }
@@ -270,21 +320,12 @@
270 320 if (!isset($scriptFile['scriptTyp'])) {
271 321 $this->addScriptInLoadedScriptsList($scriptFile);
272 322 continue;
273 323 }
274 - if ('init' === $scriptFile['scriptTyp']) {
324 + if ('custom' === $scriptFile['scriptTyp'] && Helpers::property_exists_nested($fld['field'], $scriptFile['path'], true)) {
275 325 $scriptFile['field'] = $fld['field'];
276 326 $scriptFile['fk'] = $fld['fk'];
277 - $scriptFile['formID'] = $fld['formID'];
278 327 $scriptFile['contentId'] = $fld['contentId'];
279 - $fld['field']->fldConfigs = self::generateFieldConfig($fld['fk'], $fld['field'], $fld['formID']);
280 - $this->_loadedScriptsList[] = $scriptFile;
281 - continue;
282 - }
283 - if ('custom' === $scriptFile['scriptTyp']) {
284 - $scriptFile['field'] = $fld['field'];
285 - $scriptFile['fk'] = $fld['fk'];
286 - $scriptFile['contentId'] = $fld['contentId'];
287 328 $this->addScriptInLoadedScriptsList($scriptFile);
288 329 }
289 330 }
290 331 }
@@ -290,14 +331,17 @@
290 331 }
291 332 }
292 333 }
293 334
294 - private static function getCustomJsCodes($contentIds = []) {
295 - $script = 'let bfContentId = "", bfVars= "";';
335 + private static function getCustomJsCodes($contentIds = [])
336 + {
337 + $script = 'let bfContentId = "", bfSlNo = "1", bfVars= "";';
296 338 foreach ($contentIds as $contentId) {
297 - $jsCode = self::getCustomCodes(explode('_', $contentId)[1])['JavaScript'];
339 + $contentIdArr = explode('_', $contentId);
340 + $jsCode = self::getCustomCodes($contentIdArr[1])['JavaScript'];
341 + $bfSlNo = array_key_exists(3, $contentIdArr) ? $contentIdArr[3] : '1';
298 342 if (!empty($jsCode)) {
299 - $script .= " bfContentId = '{$contentId}'; bfVars = window.bf_globals.{$contentId}.smartTags; {$jsCode}";
343 + $script .= " if(bfSelect('#{$contentId}')){ bfContentId = '{$contentId}'; bfSlNo = '{$bfSlNo}'; bfVars = window.bf_globals.{$contentId}.smartTags; {$jsCode}}";
300 344 }
301 345 }
302 346
303 347 return $script;
@@ -302,9 +346,10 @@
302 346
303 347 return $script;
304 348 }
305 349
306 - private static function getFileFromAssetsJs($fileName) {
350 + private static function getFileFromAssetsJs($fileName)
351 + {
307 352 $sourceJsFile = BITFORMS_PLUGIN_DIR_PATH . 'assets' . DIRECTORY_SEPARATOR . $fileName;
308 353 if (file_exists($sourceJsFile)) {
309 354 return file_get_contents($sourceJsFile);
310 355 }
@@ -311,9 +356,10 @@
311 356 Log::debug_log('file not found: ' . $fileName);
312 357 return false;
313 358 }
314 359
315 - public static function saveCssFile($formId, $atomicCssText) {
360 + public static function saveCssFile($formId, $atomicCssText)
361 + {
316 362 $path = 'form-styles';
317 363 $fileName = "bitform-$formId.css";
318 364 if (!isset($formId) || '' === $formId) {
319 365 return new WP_Error('missing_form_id', __('Error Occurred, Please Reload', 'bit-form'));
@@ -320,13 +366,15 @@
320 366 }
321 367 return Helpers::saveFile($path, $fileName, $atomicCssText, 'w');
322 368 }
323 369
324 - public static function customCodeFile($formId, $customCodes) {
370 + public static function customCodeFile($formId, $customCodes)
371 + {
325 372 // for js file
326 373 $path = 'form-scripts';
327 374 $fileName = "bitform-custom-$formId.js";
328 - self::customCodeFileSaveOrDelete($customCodes->JavaScript, $path, $fileName);
375 + $filteredJs = Helpers::removeJsSingleLineComments($customCodes->JavaScript);
376 + self::customCodeFileSaveOrDelete($filteredJs, $path, $fileName);
329 377
330 378 // for css file
331 379 $path = 'form-styles';
332 380 $fileName = "bitform-custom-$formId.css";
@@ -334,22 +382,22 @@
334 382
335 383 return true;
336 384 }
337 385
338 - private static function customCodeFileSaveOrDelete($script, $path, $fileName) {
386 + public static function customCodeFileSaveOrDelete($script, $path, $fileName)
387 + {
339 388 if ($script) {
340 389 Helpers::saveFile($path, $fileName, $script, 'w');
341 390 } else {
342 391 $uploadPath = "$path/$fileName";
343 392 $uploadFilePath = Helpers::generatePathDirOrFile($uploadPath);
344 - if (file_exists($uploadFilePath)) {
345 - unlink($uploadFilePath);
346 - }
393 + FileHandler::deleteIsFileExists($uploadFilePath);
347 394 }
348 395 return true;
349 396 }
350 397
351 - public static function getCustomCodes($formId) {
398 + public static function getCustomCodes($formId)
399 + {
352 400 $customCodes = ['JavaScript' => '', 'CSS' => ''];
353 401 $customJsPath = Helpers::generatePathDirOrFile("form-scripts/bitform-custom-$formId.js");
354 402 $customCodes['JavaScript'] = Helpers::fileRead($customJsPath);
355 403
@@ -358,70 +406,222 @@
358 406
359 407 return $customCodes;
360 408 }
361 409
362 - public static function generateFieldConfig($fieldKey, $field, $formID) {
363 - $fieldType = $field->typ;
364 - $missingConfigs = ScriptFilePriorityManager::fieldMissingConfigsProps($fieldType, $field) ?: [];
365 - $hasConfigProp = in_array('config', $missingConfigs);
366 - $fldConf = (object) [];
367 - if (false === $hasConfigProp && isset($field->config)) {
368 - $fldConf = $field->config;
410 + private $fldContainersByType = [
411 + 'select' => '.__$fk__-dpd-fld-wrp',
412 + 'country' => '.__$fk__-country-fld-wrp',
413 + 'currency' => '.__$fk__-currency-fld-wrp',
414 + 'phone-number' => '.__$fk__-phone-fld-wrp',
415 + 'file-up' => '.__$fk__-file-up-wrpr',
416 + 'advanced-file-up' => '#filepond-__$fk__-container',
417 + 'paypal' => '.__$fk__-paypal-wrp',
418 + 'razorpay' => '.__$fk__-razorpay-wrp',
419 + 'recaptcha' => '.__$fk__-recaptcha-wrp',
420 + 'stripe' => '.__$fk__-stripe-fld',
421 + 'mollie' => '.__$fk__-mollie-wrp',
422 + 'repeater' => '.__$fk__-rpt-fld-wrp',
423 + 'signature' => '.__$fk__-inp-fld-wrp',
424 + 'rating' => '.__$fk__-inp-fld-wrp',
425 + 'hcaptcha' => '.__$fk__-h-captcha-wrp',
426 + 'advanced-datetime' => '.__$fk__-advanced-datetime',
427 + ];
428 +
429 + private function generateFieldConfigsJs()
430 + {
431 + $customFlds = ['select', 'country', 'currency', 'phone-number', 'file-up', 'advanced-file-up', 'paypal', 'razorpay', 'stripe', 'mollie', 'recaptcha', 'repeater', 'signature', 'rating', 'turnstile', 'hcaptcha', 'advanced-datetime'];
432 + $allFieldTypes = array_keys($this->_fields);
433 + $customFldsInForms = array_intersect($allFieldTypes, $customFlds);
434 + $formContents = $this->_formContents;
435 + $recaptchaV3Enabled = false;
436 + foreach ($formContents as $content) {
437 + if (isset($content->additional->enabled->recaptchav3) && $content->additional->enabled->recaptchav3) {
438 + $recaptchaV3Enabled = true;
439 + break;
440 + }
369 441 }
370 - $vars = ['fieldKey' => $fieldKey, 'formID' => $formID];
371 - foreach ($missingConfigs as $confPath => $fldPath) {
372 - $value = '';
373 - if (isset($fldPath['var']) && $vars[$fldPath['var']]) {
374 - $value = $vars[$fldPath['var']];
442 + if (empty($customFldsInForms) && !$recaptchaV3Enabled) {
443 + return '';
444 + }
445 +
446 + $containers = [];
447 + foreach ($customFldsInForms as $customFldTyp) {
448 + if (isset($this->fldContainersByType[$customFldTyp])) {
449 + $containers[$customFldTyp] = $this->fldContainersByType[$customFldTyp];
375 450 }
376 - if (empty($value) && isset($fldPath['path'])) {
377 - $value = Helpers::getDataFromNestedPath($field, $fldPath['path']);
451 + }
452 +
453 + $customFldConfigPaths = [];
454 +
455 + foreach ($customFldsInForms as $customFldTyp) {
456 + $allConfs = ScriptFilePriorityManager::getAllFldConfs();
457 + if (isset($allConfs[$customFldTyp])) {
458 + $customFldConfigPaths[$customFldTyp] = $allConfs[$customFldTyp];
459 + } else {
460 + $customFldConfigPaths[$customFldTyp] = (object) [];
378 461 }
379 - if (empty($value) && isset($fldPath['val'])) {
380 - $value = $fldPath['val'];
381 - }
382 - $fldConf = Helpers::setDataToNestedPath($fldConf, $confPath, $value);
383 462 }
384 - return $fldConf;
385 - }
386 463
387 - private function getJsFuncForValidation() {
388 - $validationCmnFunc = ScriptFilePriorityManager::validationCommonFunction();
389 - foreach ($validationCmnFunc as $funcName => $funcArr) {
390 - // get need validation function from validationScriptFile()
391 - $scriptFile = $this->_validationJsFilesNeeded[$funcName];
392 - if (isset($funcArr['notFields'])) {
393 - if (is_array($funcArr['notFields'])) {
394 - foreach ($funcArr['notFields'] as $notField) {
395 - if (!isset($this->_fields[$notField])) {
396 - $this->addScriptInLoadedScriptsList($scriptFile);
397 - }
464 + $customFldConfigPaths = wp_json_encode($customFldConfigPaths);
465 + $containers = wp_json_encode($containers);
466 +
467 + $scriptLoaderFields = ['paypal', 'razorpay', 'stripe', 'recaptcha', 'turnstile', 'hcaptcha'];
468 + $scriptLoadedNeeded = array_intersect($scriptLoaderFields, $customFldsInForms) || $recaptchaV3Enabled;
469 + if ($scriptLoadedNeeded) {
470 + $scriptLoaderJs = ScriptLoader::init();
471 + } else {
472 + $scriptLoaderJs = '';
473 + }
474 +
475 + if (in_array('paypal', $customFldsInForms)) {
476 + $paypalInitJs = Paypal::init();
477 + } else {
478 + $paypalInitJs = '';
479 + }
480 +
481 + if (in_array('razorpay', $customFldsInForms)) {
482 + $razorpayInitJs = Razorpay::init();
483 + } else {
484 + $razorpayInitJs = '';
485 + }
486 +
487 + if (in_array('stripe', $customFldsInForms)) {
488 + $stripeInitJs = Stripe::init();
489 + } else {
490 + $stripeInitJs = '';
491 + }
492 +
493 + if (in_array('mollie', $customFldsInForms)) {
494 + $mollieInitJs = Stripe::init();
495 + } else {
496 + $mollieInitJs = '';
497 + }
498 +
499 + if (in_array('recaptcha', $customFldsInForms)) {
500 + $recaptchaInitJs = Recaptcha::init();
501 + } else {
502 + $recaptchaInitJs = '';
503 + }
504 +
505 + if (in_array('turnstile', $customFldsInForms)) {
506 + $turnstileInitJs = Turnstile::init();
507 + } else {
508 + $turnstileInitJs = '';
509 + }
510 +
511 + if (in_array('hcaptcha', $customFldsInForms)) {
512 + $hCaptchaInitJs = HCaptcha::init();
513 + } else {
514 + $hCaptchaInitJs = '';
515 + }
516 +
517 + if ($recaptchaV3Enabled) {
518 + $recaptchaV3InitJs = RecaptchaV3::init();
519 + } else {
520 + $recaptchaV3InitJs = '';
521 + }
522 +
523 + $script = <<<FIELDCONFIGJS
524 + const customFldConfigPaths = $customFldConfigPaths;
525 + const fldContainers = $containers;
526 +
527 + $scriptLoaderJs;
528 +
529 + function initAllCustomFlds (formContentId = null) {
530 + const allContendIds = formContentId ? [formContentId] : Object.keys(bf_globals);
531 + allContendIds.forEach((contentId) => {
532 + const contentData = bf_globals[contentId];
533 + const flds = bf_globals[contentId]?.fields || {};
534 + const fldKeys = Object.keys(flds).reverse();
535 + fldKeys.forEach((fldKey) => {
536 + const fldData = flds[fldKey];
537 + const fldType = fldData.typ;
538 + if(fldType === 'paypal') {
539 + $paypalInitJs;
540 + } else if(fldType === 'razorpay') {
541 + $razorpayInitJs;
542 + } else if(fldType === 'recaptcha') {
543 + $recaptchaInitJs;
544 + } else if(fldType === 'turnstile') {
545 + $turnstileInitJs;
546 + } else if(fldType === 'hcaptcha') {
547 + $hCaptchaInitJs;
548 + } else if(fldType === 'stripe') {
549 + $stripeInitJs;
550 + } else if (customFldConfigPaths[fldType]) {
551 + contentData.inits[fldKey] = getFldInstance(contentId, fldKey, fldType);
398 552 }
553 + });
554 + if(contentData.gRecaptchaVersion === 'v3' && contentData.gRecaptchaSiteKey){
555 + $recaptchaV3InitJs;
399 556 }
400 - }
401 - if (isset($funcArr['fields'])) {
402 - if (is_array($funcArr['fields'])) {
403 - foreach ($funcArr['fields'] as $fieldType) {
404 - if (isset($this->_fields[$fieldType])) {
405 - // for set function array in $this->_loadedScriptsList
406 - $this->addScriptInLoadedScriptsList($scriptFile);
407 - }
557 + });
558 + };
559 + function getFldInstance(contentId, fldKey, fldTyp, nestedSelector = '') {
560 + const fldClass = this['bit_'+fldTyp.replace(/-/g, '_')+'_field'];
561 + const selector = '#form-'+contentId+' '+nestedSelector+fldContainers[fldTyp].replace("__\$fk__", fldKey);
562 + if(!fldClass || !bfSelect(selector)) return;
563 + return new fldClass(selector, getFldConf(contentId, fldKey, fldTyp));
564 + };
565 + function getFldConf(contentId, fieldKey, fldTyp) {
566 + const fldData = bf_globals[contentId].fields[fieldKey];
567 + const fldConfPaths = Object.entries(customFldConfigPaths[fldTyp]);
568 + let fldConf = {};
569 + const { formId } = bf_globals[contentId];
570 + if (!("config" in customFldConfigPaths[fldTyp]) && "config" in fldData) fldConf = fldData.config;
571 + const varData = { contentId, fieldKey, formId };
572 + fldConfPaths.forEach(([ confPath, fldPath ]) => {
573 + let value = "";
574 + if (fldPath.var) value = varData[fldPath.var];
575 + if (!value && fldPath.path) {
576 + if(Array.isArray(fldPath.path)) {
577 + fldPath.path.forEach((path) => {
578 + if(!value) value = getDataFromNestedPath(fldData, path);
579 + });
580 + } else {
581 + value = getDataFromNestedPath(fldData, fldPath.path);
408 582 }
409 - } else {
410 - // for all field types
411 - $this->addScriptInLoadedScriptsList($scriptFile);
412 583 }
413 - }
414 -
415 - if (isset($funcArr['dependencies'])) {
416 - foreach ($funcArr['dependencies'] as $dependency) {
417 - $this->addScriptInLoadedScriptsList($dependency);
584 + if (!value && fldPath.val) {
585 + value = fldPath.val;
586 + if(typeof value === 'string') {
587 + Object.entries(varData).forEach(([key, val]) => {
588 + value = value.replace("__\$"+key+"__", val);
589 + });
590 + }
418 591 }
592 + fldConf = setDataToNestedPath(fldConf, confPath, value);
593 + });
594 + return fldConf;
595 + };
596 + function getDataFromNestedPath(data, key) {
597 + const keys = key.split("->");
598 + const lastKey = keys.pop();
599 + let current = {...data};
600 + for (const k of keys) {
601 + if (!(k in current)) return null;
602 + current = current[k];
419 603 }
604 + return current[lastKey] || null;
420 605 }
606 + function setDataToNestedPath(data, key, value) {
607 + const keys = key.split("->");
608 + const lastKey = keys.pop();
609 + let current = {...data};
610 + keys.forEach((k) => {
611 + if (!current[k]) current[k] = {};
612 + current = current[k];
613 + });
614 + current[lastKey] = value;
615 + return current;
616 + }
617 +FIELDCONFIGJS;
618 +
619 + return $script;
421 620 }
422 621
423 - private function addScriptInLoadedScriptsList($fileArr) {
622 + private function addScriptInLoadedScriptsList($fileArr)
623 + {
424 624 $fileName = $fileArr['filename'];
425 625 if (!in_array($fileName, $this->_scriptAddedFlags)) {
426 626 $this->_loadedScriptsList[] = $fileArr;
427 627 $this->_scriptAddedFlags[] = $fileName;
@@ -428,26 +628,32 @@
428 628 }
429 629 return true;
430 630 }
431 631
432 - private function jsFrontendScript() {
632 + private function jsFrontendScript()
633 + {
433 634 foreach ($this->_formContents as $formContent) {
434 635 if (Helpers::property_exists_nested($formContent, 'workFlowExist->oninput', true)) {
435 - $fileArr = ScriptFilePriorityManager::validationScriptFile()['conditionalLogic'];
636 + $fileArr = ScriptFilePriorityManager::validationAndOtherScriptFile()['conditionalLogic'];
436 637 $this->addScriptInLoadedScriptsList($fileArr);
437 - $fileArr = ScriptFilePriorityManager::validationScriptFile()['validateFocusLost'];
638 + $fileArr = ScriptFilePriorityManager::validationAndOtherScriptFile()['resetPlaceholders'];
438 639 $this->addScriptInLoadedScriptsList($fileArr);
640 + $fileArr = ScriptFilePriorityManager::validationAndOtherScriptFile()['bfResetDefaultValue'];
641 + $this->addScriptInLoadedScriptsList($fileArr);
642 + $fileArr = ScriptFilePriorityManager::validationAndOtherScriptFile()['validateFocusLost'];
643 + $this->addScriptInLoadedScriptsList($fileArr);
439 644 $fileArr = ScriptFilePriorityManager::frontendScriptFile()['observeElm'];
440 645 $this->addScriptInLoadedScriptsList($fileArr);
441 646 }
442 647 if (Helpers::property_exists_nested($formContent, 'additional->enabled->validateFocusLost', true)) {
443 - $fileArr = ScriptFilePriorityManager::validationScriptFile()['validateFocusLost'];
648 + $fileArr = ScriptFilePriorityManager::validationAndOtherScriptFile()['validateFocusLost'];
444 649 $this->addScriptInLoadedScriptsList($fileArr);
445 650 }
446 651 }
447 652 }
448 653
449 - private function jsHiddenFieldScript() {
654 + private function jsHiddenFieldScript()
655 + {
450 656 $appConfig = get_option('bitform_app_config');
451 657 if (Helpers::property_exists_nested($appConfig, 'cache_plugin', true)) {
452 658 $fileArr = ScriptFilePriorityManager::frontendScriptFile()['hidden-token-field'];
453 659 $this->addScriptInLoadedScriptsList($fileArr);
@@ -454,9 +660,10 @@
454 660 return;
455 661 }
456 662 }
457 663
458 - public function dd($data, $exit = false) {
664 + public function dd($data, $exit = false)
665 + {
459 666 echo '+++++++++++++';
460 667 echo '<pre>';
461 668 var_dump($data);
462 669 echo '</pre>';