| 1 |
<?php |
| 2 |
|
| 3 |
namespace BitCode\BitForm\Admin\Form; |
| 4 |
|
| 5 |
if (!defined('ABSPATH')) { |
| 6 |
exit; |
| 7 |
} |
| 8 |
|
| 9 |
use BitCode\BitForm\Core\Util\FileHandler; |
| 10 |
use BitCode\BitForm\Core\Util\Log; |
| 11 |
use WP_Error; |
| 12 |
|
| 13 |
class FrontEndScriptGenerator |
| 14 |
{ |
| 15 |
private $_scriptAddedFlags; |
| 16 |
private $_fields; |
| 17 |
private $_formContents; |
| 18 |
private $_jsFilesNeeded; |
| 19 |
private $_loadedScriptsList; |
| 20 |
private $_validationJsFilesNeeded; |
| 21 |
|
| 22 |
public function __construct() |
| 23 |
{ |
| 24 |
$this->_scriptAddedFlags = []; |
| 25 |
$this->_fields = []; |
| 26 |
$this->_jsFilesNeeded = []; |
| 27 |
$this->_loadedScriptsList = []; |
| 28 |
$this->_validationJsFilesNeeded = ScriptFilePriorityManager::validationAndOtherScriptFile(); |
| 29 |
} |
| 30 |
|
| 31 |
private static function generateBfGlobalObjJS($contentIds = []) |
| 32 |
{ |
| 33 |
$contentidArray = wp_json_encode($contentIds); |
| 34 |
return ' if(!window.bf_globals){ window.bf_globals = {};} |
| 35 |
(function(){ |
| 36 |
var bfSetupGlobals = function(){ |
| 37 |
' . $contentidArray . '.forEach(function(contentId){ |
| 38 |
const form = document.getElementById(contentId); |
| 39 |
if(!form){ |
| 40 |
delete window.bf_globals[contentId]; |
| 41 |
return; |
| 42 |
} |
| 43 |
if(!window.bf_globals[contentId]){ |
| 44 |
window.bf_globals[contentId] = {inits: {}, contentId: contentId}; |
| 45 |
}else{ |
| 46 |
window.bf_globals[contentId].inits = {}; |
| 47 |
window.bf_globals[contentId].contentId = contentId; |
| 48 |
} |
| 49 |
}); |
| 50 |
}; |
| 51 |
// Wait for DOM ready: optimizers can run this before the form markup is |
| 52 |
// parsed, and the not-found branch would then delete arrived config. |
| 53 |
if(document.readyState === "loading"){ |
| 54 |
document.addEventListener("DOMContentLoaded", bfSetupGlobals); |
| 55 |
} else { |
| 56 |
bfSetupGlobals(); |
| 57 |
} |
| 58 |
})();'; |
| 59 |
} |
| 60 |
|
| 61 |
private static function isValidationNeeded($fldData) |
| 62 |
{ |
| 63 |
$validationsToCheck = ['valid->req', 'valid->regexr', 'mn', 'mx', 'opt', 'err->invalid->show', 'err->notVerified->show']; |
| 64 |
foreach ($validationsToCheck as $property) { |
| 65 |
$needValidation = Helpers::property_exists_nested($fldData, $property); |
| 66 |
if ($needValidation) { |
| 67 |
return true; |
| 68 |
} |
| 69 |
} |
| 70 |
return false; |
| 71 |
} |
| 72 |
|
| 73 |
public function generateJsFile($formContents, $fields, $contentIds, $postId, $formIDs = null, $preview = 'classic') |
| 74 |
{ |
| 75 |
add_option('bitforms_frontend_js_generating', true); |
| 76 |
$this->_formContents = $formContents; |
| 77 |
$this->_fields = $fields; |
| 78 |
|
| 79 |
$this->appendJs(self::generateBfGlobalObjJS($contentIds), $postId, $preview, 'w'); |
| 80 |
$this->_jsFilesNeeded = ScriptFilePriorityManager::jsFile(); |
| 81 |
|
| 82 |
// helper js files for whole form |
| 83 |
foreach ($this->_jsFilesNeeded['helperScript'] as $jsFile) { |
| 84 |
$this->addScriptInLoadedScriptsList($jsFile); |
| 85 |
} |
| 86 |
|
| 87 |
// for add validation js files |
| 88 |
$this->jsValidationNeededFile(); |
| 89 |
|
| 90 |
// js files for all fields |
| 91 |
$this->jsFieldsNeededFile(); |
| 92 |
|
| 93 |
// for frontend helper js files |
| 94 |
$this->jsFrontendScript(); |
| 95 |
|
| 96 |
// for hidden Field when cache plugin on |
| 97 |
$this->jsHiddenFieldScript(); |
| 98 |
|
| 99 |
// for recaptcha v3 (form-level setting) |
| 100 |
$this->jsRecaptchaV3Scripts(); |
| 101 |
|
| 102 |
// for form abandonment scripts |
| 103 |
$this->jsFormAbandonmentScripts(); |
| 104 |
|
| 105 |
// multi step form scripts |
| 106 |
$this->multiStepFormScripts(); |
| 107 |
|
| 108 |
// conversational form scripts |
| 109 |
$this->conversationalFormScripts(); |
| 110 |
|
| 111 |
//⚠👆 every script file generate method call before this method |
| 112 |
$this->appendJs($this->getScript(), $postId, $preview); |
| 113 |
$this->appendJs($this->generateFieldConfigsJs($contentIds), $postId, $preview); |
| 114 |
// init all js events and functions at last |
| 115 |
$this->appendJs(self::getFileFromAssetsJs('bitform-init.min.js'), $postId, $preview); |
| 116 |
// picks up forms injected after load (AJAX, popups, lazy content) |
| 117 |
$this->appendJs(self::getFileFromAssetsJs('bitform-observer.min.js'), $postId, $preview); |
| 118 |
if (defined('ELEMENTOR_PRO_VERSION')) { |
| 119 |
$this->appendJs(self::getFileFromAssetsJs('bitform-elementor.min.js'), $postId, $preview); |
| 120 |
} |
| 121 |
|
| 122 |
// for js file minification |
| 123 |
$this->appendJs(self::getCustomJsCodes($contentIds), $postId, $preview); |
| 124 |
delete_option('bitforms_frontend_js_generating'); |
| 125 |
return true; |
| 126 |
} |
| 127 |
|
| 128 |
private function multiStepFormScripts() |
| 129 |
{ |
| 130 |
foreach ($this->_formContents as $formContent) { |
| 131 |
$layout = $formContent->layout; |
| 132 |
if (is_array($layout) && count($layout) > 1) { |
| 133 |
$files = ScriptFilePriorityManager::multiStepFiles(); |
| 134 |
foreach ($files as $file) { |
| 135 |
$this->addScriptInLoadedScriptsList($file); |
| 136 |
} |
| 137 |
} |
| 138 |
} |
| 139 |
} |
| 140 |
|
| 141 |
private function conversationalFormScripts() |
| 142 |
{ |
| 143 |
foreach ($this->_formContents as $formContent) { |
| 144 |
if (!empty($formContent->formInfo->conversationalSettings) && $formContent->formInfo->conversationalSettings->enable) { |
| 145 |
$files = ScriptFilePriorityManager::conversationalFormFiles(); |
| 146 |
foreach ($files as $file) { |
| 147 |
$this->addScriptInLoadedScriptsList($file); |
| 148 |
} |
| 149 |
} |
| 150 |
} |
| 151 |
} |
| 152 |
|
| 153 |
private function jsFormAbandonmentScripts() |
| 154 |
{ |
| 155 |
/** |
| 156 |
* Add-ons can inject required script files here. |
| 157 |
* |
| 158 |
* @param array $files Array of file arrays: ['priority' => int, 'filename' => string] |
| 159 |
* @param array $formContents |
| 160 |
* @param array $fields |
| 161 |
*/ |
| 162 |
$files = apply_filters('bitform_form_abandonment_script_files', [], $this->_formContents, $this->_fields); |
| 163 |
if (empty($files) || !is_array($files)) { |
| 164 |
return; |
| 165 |
} |
| 166 |
foreach ($files as $jsFile) { |
| 167 |
if (!empty($jsFile['filename']) && !empty($jsFile['priority'])) { |
| 168 |
$this->addScriptInLoadedScriptsList($jsFile); |
| 169 |
} |
| 170 |
} |
| 171 |
} |
| 172 |
|
| 173 |
private function appendJs($script, $postId, $previewMode, $mode = 'a') |
| 174 |
{ |
| 175 |
$fileName = ''; |
| 176 |
$path = ''; |
| 177 |
|
| 178 |
if ('conversational' === $previewMode) { |
| 179 |
$fileName = "bitform-conversational-{$postId}.js"; |
| 180 |
$path = 'form-scripts'; |
| 181 |
} elseif ('preview' === $previewMode) { |
| 182 |
$fileName = "preview-{$postId}.js"; |
| 183 |
$path = 'form-scripts'; |
| 184 |
} else { |
| 185 |
$fileName = "bitform-js-$postId.js"; |
| 186 |
$path = "form-scripts/{$postId}"; |
| 187 |
} |
| 188 |
Helpers::saveFile($path, $fileName, Helpers::minifyJs($script), $mode); |
| 189 |
} |
| 190 |
|
| 191 |
private function getScript() |
| 192 |
{ |
| 193 |
usort($this->_loadedScriptsList, function ($a, $b) { |
| 194 |
return $a['priority'] - $b['priority']; |
| 195 |
}); |
| 196 |
|
| 197 |
$script = ''; |
| 198 |
foreach ($this->_loadedScriptsList as $scriptFileArr) { |
| 199 |
$fileNam = $scriptFileArr['filename']; |
| 200 |
$fileContent = self::getFileFromAssetsJs($fileNam); |
| 201 |
if ($fileContent) { |
| 202 |
$script .= $fileContent; |
| 203 |
} |
| 204 |
} |
| 205 |
return $script; |
| 206 |
} |
| 207 |
|
| 208 |
private function jsValidationNeededFile() |
| 209 |
{ |
| 210 |
foreach ($this->_fields as $flds) { |
| 211 |
foreach ($flds as $fld) { |
| 212 |
$fldData = $fld['field']; |
| 213 |
// Corrupt/partial form JSON can produce a null field or one without typ. |
| 214 |
if (!is_object($fldData)) { |
| 215 |
continue; |
| 216 |
} |
| 217 |
// for validation js files |
| 218 |
if (self::isValidationNeeded($fldData)) { |
| 219 |
$validation = $this->_validationJsFilesNeeded['validation']; |
| 220 |
$this->addScriptInLoadedScriptsList($validation); |
| 221 |
} |
| 222 |
// for required |
| 223 |
if (Helpers::property_exists_nested($fldData, 'valid->req')) { |
| 224 |
$fileArr = $this->_validationJsFilesNeeded['requiredFldValidation']; |
| 225 |
$this->addScriptInLoadedScriptsList($fileArr); |
| 226 |
} |
| 227 |
// for regex |
| 228 |
if (Helpers::property_exists_nested($fldData, 'valid->regexr')) { |
| 229 |
$patternFile = $this->_validationJsFilesNeeded['generateBackslashPattern']; |
| 230 |
$rgx = $this->_validationJsFilesNeeded['regexPatternValidation']; |
| 231 |
$this->addScriptInLoadedScriptsList($patternFile); |
| 232 |
$this->addScriptInLoadedScriptsList($rgx); |
| 233 |
} |
| 234 |
|
| 235 |
$validationScriptFileMapping = ScriptFilePriorityManager::validationScriptFileMapping($fldData->typ); |
| 236 |
if ($validationScriptFileMapping) { |
| 237 |
foreach ($validationScriptFileMapping as $key => $value) { |
| 238 |
$paths = $value['paths'] ?? []; |
| 239 |
$hasMatchingPath = false; |
| 240 |
foreach ($paths as $path) { |
| 241 |
if (Helpers::property_exists_nested($fldData, $path)) { |
| 242 |
$hasMatchingPath = true; |
| 243 |
break; // one match is enough |
| 244 |
} |
| 245 |
} |
| 246 |
|
| 247 |
if (!$hasMatchingPath) { |
| 248 |
continue; |
| 249 |
} |
| 250 |
|
| 251 |
// Add the main script once |
| 252 |
if (!empty($this->_validationJsFilesNeeded[$key])) { |
| 253 |
$this->addScriptInLoadedScriptsList($this->_validationJsFilesNeeded[$key]); |
| 254 |
} |
| 255 |
|
| 256 |
// Add dependencies once each |
| 257 |
foreach (($value['dependencies'] ?? []) as $dep) { |
| 258 |
if (!empty($this->_validationJsFilesNeeded[$dep])) { |
| 259 |
$this->addScriptInLoadedScriptsList($this->_validationJsFilesNeeded[$dep]); |
| 260 |
} |
| 261 |
} |
| 262 |
} |
| 263 |
} |
| 264 |
} |
| 265 |
} |
| 266 |
} |
| 267 |
|
| 268 |
private function jsFieldsNeededFile() |
| 269 |
{ |
| 270 |
$filePondPluginList = apply_filters('bitform_filepond_plugins_list', []); |
| 271 |
foreach ($this->_fields as $typ => $flds) { |
| 272 |
if (!array_key_exists($typ, $this->_jsFilesNeeded)) { |
| 273 |
continue; |
| 274 |
} |
| 275 |
$fldScriptArr = $this->_jsFilesNeeded[$typ]; |
| 276 |
|
| 277 |
foreach ($flds as $fld) { |
| 278 |
if ('advanced-file-up' === $typ) { |
| 279 |
$configs = $fld['field']->config; |
| 280 |
foreach ($configs as $configKey => $config) { |
| 281 |
if ($configs->$configKey) { |
| 282 |
if (array_key_exists($configKey, $filePondPluginList)) { |
| 283 |
$this->addScriptInLoadedScriptsList($filePondPluginList[$configKey]); |
| 284 |
} |
| 285 |
} |
| 286 |
} |
| 287 |
} |
| 288 |
foreach ($fldScriptArr as $scriptFile) { |
| 289 |
if (isset($scriptFile['paths']) && is_array($scriptFile['paths'])) { |
| 290 |
$pathMatched = false; |
| 291 |
foreach ($scriptFile['paths'] as $path) { |
| 292 |
if (Helpers::property_exists_nested($fld['field'], $path)) { |
| 293 |
$pathMatched = true; |
| 294 |
break; |
| 295 |
} |
| 296 |
} |
| 297 |
if (!$pathMatched) { |
| 298 |
continue; |
| 299 |
} |
| 300 |
} elseif (isset($scriptFile['path']) && !Helpers::property_exists_nested($fld['field'], $scriptFile['path'])) { |
| 301 |
continue; |
| 302 |
} |
| 303 |
$this->addScriptInLoadedScriptsList($scriptFile); |
| 304 |
} |
| 305 |
} |
| 306 |
} |
| 307 |
} |
| 308 |
|
| 309 |
private static function getCustomJsCodes($contentIds = []) |
| 310 |
{ |
| 311 |
$script = 'let bfContentId = "", bfSlNo = "1", bfVars= "";'; |
| 312 |
foreach ($contentIds as $contentId) { |
| 313 |
$contentIdArr = explode('_', $contentId); |
| 314 |
$jsCode = self::getCustomCodes($contentIdArr[1])['JavaScript']; |
| 315 |
$bfSlNo = array_key_exists(3, $contentIdArr) ? $contentIdArr[3] : '1'; |
| 316 |
if (!empty($jsCode)) { |
| 317 |
$script .= " if(bfSelect('#{$contentId}')){ bfContentId = '{$contentId}'; bfSlNo = '{$bfSlNo}'; bfVars = window.bf_globals.{$contentId}.smartTags; {$jsCode}}"; |
| 318 |
} |
| 319 |
} |
| 320 |
|
| 321 |
return $script; |
| 322 |
} |
| 323 |
|
| 324 |
private static function getFileFromAssetsJs($fileName) |
| 325 |
{ |
| 326 |
$sourceJsFile = BITFORMS_PLUGIN_DIR_PATH . 'assets' . DIRECTORY_SEPARATOR . $fileName; |
| 327 |
if (file_exists($sourceJsFile)) { |
| 328 |
return file_get_contents($sourceJsFile); |
| 329 |
} |
| 330 |
Log::debug_log('file not found: ' . $fileName); |
| 331 |
return false; |
| 332 |
} |
| 333 |
|
| 334 |
public static function saveCssFile($formId, $atomicCssText) |
| 335 |
{ |
| 336 |
$path = 'form-styles'; |
| 337 |
$fileName = "bitform-$formId.css"; |
| 338 |
if (!isset($formId) || '' === $formId) { |
| 339 |
return new WP_Error('missing_form_id', __('Error Occurred, Please Reload', 'bit-form')); |
| 340 |
} |
| 341 |
return Helpers::saveFile($path, $fileName, $atomicCssText, 'w'); |
| 342 |
} |
| 343 |
|
| 344 |
public static function customCodeFile($formId, $customCodes) |
| 345 |
{ |
| 346 |
// for js file |
| 347 |
$path = 'form-scripts'; |
| 348 |
$fileName = "bitform-custom-$formId.js"; |
| 349 |
$filteredJs = Helpers::removeJsSingleLineComments($customCodes->JavaScript); |
| 350 |
self::customCodeFileSaveOrDelete($filteredJs, $path, $fileName); |
| 351 |
|
| 352 |
// for css file |
| 353 |
$path = 'form-styles'; |
| 354 |
$fileName = "bitform-custom-$formId.css"; |
| 355 |
self::customCodeFileSaveOrDelete($customCodes->CSS, $path, $fileName); |
| 356 |
|
| 357 |
return true; |
| 358 |
} |
| 359 |
|
| 360 |
public static function customCodeFileSaveOrDelete($script, $path, $fileName) |
| 361 |
{ |
| 362 |
if ($script) { |
| 363 |
Helpers::saveFile($path, $fileName, $script, 'w'); |
| 364 |
} else { |
| 365 |
$uploadPath = "$path/$fileName"; |
| 366 |
$uploadFilePath = Helpers::generatePathDirOrFile($uploadPath); |
| 367 |
FileHandler::deleteIsFileExists($uploadFilePath); |
| 368 |
} |
| 369 |
return true; |
| 370 |
} |
| 371 |
|
| 372 |
public static function getCustomCodes($formId) |
| 373 |
{ |
| 374 |
$customCodes = ['JavaScript' => '', 'CSS' => '']; |
| 375 |
$customJsPath = Helpers::generatePathDirOrFile("form-scripts/bitform-custom-$formId.js"); |
| 376 |
$customCodes['JavaScript'] = Helpers::fileRead($customJsPath); |
| 377 |
|
| 378 |
$customCSSPath = Helpers::generatePathDirOrFile("form-styles/bitform-custom-$formId.css"); |
| 379 |
$customCodes['CSS'] = Helpers::fileRead($customCSSPath); |
| 380 |
|
| 381 |
return $customCodes; |
| 382 |
} |
| 383 |
|
| 384 |
private $fldContainersByType = [ |
| 385 |
'address' => '.__$fk__-parent-fld-wrp', |
| 386 |
'select' => '.__$fk__-dpd-fld-wrp', |
| 387 |
'country' => '.__$fk__-country-fld-wrp', |
| 388 |
'currency' => '.__$fk__-currency-fld-wrp', |
| 389 |
'phone-number' => '.__$fk__-phone-fld-wrp', |
| 390 |
'file-up' => '.__$fk__-file-up-wrpr', |
| 391 |
'advanced-file-up' => '#filepond-__$fk__-container', |
| 392 |
'paypal' => '.__$fk__-paypal-wrp', |
| 393 |
'razorpay' => '.__$fk__-razorpay-wrp', |
| 394 |
'recaptcha' => '.__$fk__-recaptcha-wrp', |
| 395 |
'stripe' => '.__$fk__-stripe-fld', |
| 396 |
'mollie' => '.__$fk__-mollie-wrp', |
| 397 |
'repeater' => '.__$fk__-rpt-fld-wrp', |
| 398 |
'signature' => '.__$fk__-inp-fld-wrp', |
| 399 |
'rating' => '.__$fk__-inp-fld-wrp', |
| 400 |
'email-otp' => '.__$fk__-inp-fld-wrp', |
| 401 |
'hcaptcha' => '.__$fk__-h-captcha-wrp', |
| 402 |
'advanced-datetime' => '.__$fk__-advanced-datetime', |
| 403 |
]; |
| 404 |
|
| 405 |
private function generateFieldConfigsJs() |
| 406 |
{ |
| 407 |
$customFlds = ['address', 'select', 'country', 'currency', 'phone-number', 'file-up', 'advanced-file-up', 'paypal', 'razorpay', 'stripe', 'mollie', 'recaptcha', 'repeater', 'signature', 'rating', 'turnstile', 'hcaptcha', 'advanced-datetime', 'email-otp']; |
| 408 |
$allFieldTypes = array_keys($this->_fields); |
| 409 |
$customFldsInForms = array_intersect($allFieldTypes, $customFlds); |
| 410 |
$formContents = $this->_formContents; |
| 411 |
$recaptchaV3Enabled = false; |
| 412 |
foreach ($formContents as $content) { |
| 413 |
if (isset($content->additional->enabled->recaptchav3) && $content->additional->enabled->recaptchav3) { |
| 414 |
$recaptchaV3Enabled = true; |
| 415 |
break; |
| 416 |
} |
| 417 |
} |
| 418 |
if (empty($customFldsInForms) && !$recaptchaV3Enabled) { |
| 419 |
return ''; |
| 420 |
} |
| 421 |
|
| 422 |
$containers = []; |
| 423 |
foreach ($customFldsInForms as $customFldTyp) { |
| 424 |
if (isset($this->fldContainersByType[$customFldTyp])) { |
| 425 |
$containers[$customFldTyp] = $this->fldContainersByType[$customFldTyp]; |
| 426 |
} |
| 427 |
} |
| 428 |
|
| 429 |
$customFldConfigPaths = []; |
| 430 |
|
| 431 |
$allConfs = ScriptFilePriorityManager::getAllFldConfs(); |
| 432 |
foreach ($customFldsInForms as $customFldTyp) { |
| 433 |
if (isset($allConfs[$customFldTyp])) { |
| 434 |
$customFldConfigPaths[$customFldTyp] = $allConfs[$customFldTyp]; |
| 435 |
} else { |
| 436 |
$customFldConfigPaths[$customFldTyp] = (object) []; |
| 437 |
} |
| 438 |
} |
| 439 |
|
| 440 |
$customFldConfigPaths = wp_json_encode($customFldConfigPaths); |
| 441 |
$containers = wp_json_encode($containers); |
| 442 |
|
| 443 |
$script = ' const customFldConfigPaths = ' . $customFldConfigPaths . '; |
| 444 |
const fldContainers = ' . $containers . '; |
| 445 |
|
| 446 |
function initAllCustomFlds (formContentId = null) { |
| 447 |
const allContendIds = formContentId ? [formContentId] : Object.keys(bf_globals); |
| 448 |
allContendIds.forEach((contentId) => { |
| 449 |
const contentData = bf_globals[contentId]; |
| 450 |
if(!contentData?.inits) contentData.inits = {}; |
| 451 |
const flds = bf_globals[contentId]?.fields || {}; |
| 452 |
const fldKeys = Object.keys(flds).reverse(); |
| 453 |
fldKeys.forEach((fldKey) => { |
| 454 |
const fldData = flds[fldKey]; |
| 455 |
const fldType = fldData.typ; |
| 456 |
if(fldType === \'paypal\') { |
| 457 |
initPaypalFld(contentId, fldKey, fldData, fldType); |
| 458 |
} else if(fldType === \'razorpay\') { |
| 459 |
initRazorpayFld(contentId, fldKey, fldType); |
| 460 |
} else if(fldType === \'recaptcha\') { |
| 461 |
initRecaptchaFld(contentId, fldKey, fldType); |
| 462 |
} else if(fldType === \'turnstile\') { |
| 463 |
initTurnstileFld(contentId, fldKey); |
| 464 |
} else if(fldType === \'hcaptcha\') { |
| 465 |
initHCaptchaFld(contentId, fldKey, fldType); |
| 466 |
} else if(fldType === \'stripe\' || fldType === \'mollie\') { |
| 467 |
initStripeFld(contentId, fldKey, fldType); |
| 468 |
} else if (customFldConfigPaths[fldType]) { |
| 469 |
contentData.inits[fldKey] = getFldInstance(contentId, fldKey, fldType); |
| 470 |
} |
| 471 |
}); |
| 472 |
if(contentData.gRecaptchaVersion === \'v3\' && contentData.gRecaptchaSiteKey){ |
| 473 |
initRecaptchaV3Fld(contentId, contentData); |
| 474 |
} |
| 475 |
}); |
| 476 |
}; |
| 477 |
function getFldInstance(contentId, fldKey, fldTyp, nestedSelector = \'\') { |
| 478 |
const fldClass = this[\'bit_\'+fldTyp.replace(/-/g, \'_\')+\'_field\']; |
| 479 |
const selector = \'#form-\'+contentId+\' \'+nestedSelector+fldContainers[fldTyp].replace("__$fk__", fldKey); |
| 480 |
if(!fldClass || !bfSelect(selector)) return; |
| 481 |
return new fldClass(selector, getFldConf(contentId, fldKey, fldTyp)); |
| 482 |
}; |
| 483 |
function getFldConf(contentId, fieldKey, fldTyp) { |
| 484 |
const fldData = bf_globals[contentId].fields[fieldKey]; |
| 485 |
const fldConfPaths = Object.entries(customFldConfigPaths[fldTyp]); |
| 486 |
let fldConf = {}; |
| 487 |
const { formId } = bf_globals[contentId]; |
| 488 |
if (!("config" in customFldConfigPaths[fldTyp]) && "config" in fldData) fldConf = fldData.config; |
| 489 |
const varData = { contentId, fieldKey, formId }; |
| 490 |
fldConfPaths.forEach(([ confPath, fldPath ]) => { |
| 491 |
let value = ""; |
| 492 |
if (fldPath.var) value = varData[fldPath.var]; |
| 493 |
if (!value && fldPath.path) { |
| 494 |
if(Array.isArray(fldPath.path)) { |
| 495 |
fldPath.path.forEach((path) => { |
| 496 |
if(!value) value = getDataFromNestedPath(fldData, path); |
| 497 |
}); |
| 498 |
} else { |
| 499 |
value = getDataFromNestedPath(fldData, fldPath.path); |
| 500 |
} |
| 501 |
} |
| 502 |
if (!value && "val" in fldPath) { |
| 503 |
value = fldPath.val; |
| 504 |
if(typeof value === \'string\') { |
| 505 |
Object.entries(varData).forEach(([key, val]) => { |
| 506 |
value = value.replace("__$"+key+"__", val); |
| 507 |
}); |
| 508 |
} |
| 509 |
} |
| 510 |
fldConf = setDataToNestedPath(fldConf, confPath, value); |
| 511 |
}); |
| 512 |
return fldConf; |
| 513 |
}; |
| 514 |
function getDataFromNestedPath(data, key) { |
| 515 |
const keys = key.split("->"); |
| 516 |
const lastKey = keys.pop(); |
| 517 |
let current = {...data}; |
| 518 |
for (const k of keys) { |
| 519 |
if (!(k in current)) return null; |
| 520 |
current = current[k]; |
| 521 |
} |
| 522 |
return current[lastKey] || null; |
| 523 |
} |
| 524 |
function setDataToNestedPath(data, key, value) { |
| 525 |
const keys = key.split("->"); |
| 526 |
const lastKey = keys.pop(); |
| 527 |
let current = {...data}; |
| 528 |
keys.forEach((k) => { |
| 529 |
if (!current[k]) current[k] = {}; |
| 530 |
current = current[k]; |
| 531 |
}); |
| 532 |
current[lastKey] = value; |
| 533 |
return current; |
| 534 |
}'; |
| 535 |
|
| 536 |
return $script; |
| 537 |
} |
| 538 |
|
| 539 |
private function addScriptInLoadedScriptsList($fileArr) |
| 540 |
{ |
| 541 |
$fileName = $fileArr['filename']; |
| 542 |
if (!in_array($fileName, $this->_scriptAddedFlags)) { |
| 543 |
$this->_loadedScriptsList[] = $fileArr; |
| 544 |
$this->_scriptAddedFlags[] = $fileName; |
| 545 |
} |
| 546 |
return true; |
| 547 |
} |
| 548 |
|
| 549 |
private function jsFrontendScript() |
| 550 |
{ |
| 551 |
foreach ($this->_formContents as $formContent) { |
| 552 |
if (Helpers::property_exists_nested($formContent, 'workFlowExist->oninput', true)) { |
| 553 |
$fileArr = ScriptFilePriorityManager::validationAndOtherScriptFile()['conditionalLogic']; |
| 554 |
$this->addScriptInLoadedScriptsList($fileArr); |
| 555 |
$fileArr = ScriptFilePriorityManager::validationAndOtherScriptFile()['resetPlaceholders']; |
| 556 |
$this->addScriptInLoadedScriptsList($fileArr); |
| 557 |
$fileArr = ScriptFilePriorityManager::validationAndOtherScriptFile()['bfResetDefaultValue']; |
| 558 |
$this->addScriptInLoadedScriptsList($fileArr); |
| 559 |
$fileArr = ScriptFilePriorityManager::validationAndOtherScriptFile()['validateFocusLost']; |
| 560 |
$this->addScriptInLoadedScriptsList($fileArr); |
| 561 |
$fileArr = ScriptFilePriorityManager::frontendScriptFile()['observeElm']; |
| 562 |
$this->addScriptInLoadedScriptsList($fileArr); |
| 563 |
} |
| 564 |
if (Helpers::property_exists_nested($formContent, 'additional->enabled->validateFocusLost', true)) { |
| 565 |
$fileArr = ScriptFilePriorityManager::validationAndOtherScriptFile()['validateFocusLost']; |
| 566 |
$this->addScriptInLoadedScriptsList($fileArr); |
| 567 |
} |
| 568 |
} |
| 569 |
} |
| 570 |
|
| 571 |
private function jsHiddenFieldScript() |
| 572 |
{ |
| 573 |
$appConfig = get_option('bitform_app_config'); |
| 574 |
$cacheTokenEnabled = true; |
| 575 |
if (is_object($appConfig) && property_exists($appConfig, 'cache_plugin')) { |
| 576 |
$cacheTokenEnabled = (bool) $appConfig->cache_plugin; |
| 577 |
} elseif (is_array($appConfig) && array_key_exists('cache_plugin', $appConfig)) { |
| 578 |
$cacheTokenEnabled = (bool) $appConfig['cache_plugin']; |
| 579 |
} |
| 580 |
if ($cacheTokenEnabled) { |
| 581 |
$fileArr = ScriptFilePriorityManager::frontendScriptFile()['hidden-token-field']; |
| 582 |
$this->addScriptInLoadedScriptsList($fileArr); |
| 583 |
return; |
| 584 |
} |
| 585 |
} |
| 586 |
|
| 587 |
private function jsRecaptchaV3Scripts() |
| 588 |
{ |
| 589 |
foreach ($this->_formContents as $content) { |
| 590 |
if (isset($content->additional->enabled->recaptchav3) && $content->additional->enabled->recaptchav3) { |
| 591 |
$this->addScriptInLoadedScriptsList(['priority' => 302, 'filename' => 'scriptLoader.min.js']); |
| 592 |
$this->addScriptInLoadedScriptsList(['priority' => 303, 'filename' => 'initRecaptchaV3Fld.min.js']); |
| 593 |
return; |
| 594 |
} |
| 595 |
} |
| 596 |
} |
| 597 |
} |
| 598 |
|