# bit-form/2.0/includes/Admin/Form/FrontEndScriptGenerator.php

Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator &amp; Custom Form Builder, version 2.0. 467 lines.

- Page: https://pluginprobe.com/plugins/bit-form/2.0/code/includes/Admin/Form/FrontEndScriptGenerator.php
- Raw: https://pluginprobe.com/plugins/bit-form/2.0/raw/includes/Admin/Form/FrontEndScriptGenerator.php
- Modified: 2023-02-28T14:03:48+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/bit-form/2.0/code/includes/Admin/Form/FrontEndScriptGenerator.php#L10-L20`.

```php
<?php

namespace BitCode\BitForm\Admin\Form;

use BitCode\BitForm\Admin\Form\InitJs\RecaptchaV3;
use BitCode\BitForm\Core\Form\FormManager;
use BitCode\BitForm\Core\Integration\IntegrationHandler;
use BitCode\BitForm\Core\Util\Log;
use WP_Error;

class FrontEndScriptGenerator {
  private $_scriptAddedFlags;
  private $_fields;
  private $_formContents;
  private $_jsFilesNeeded;
  private $_loadedScriptsList;
  private $_validationJsFilesNeeded;

  public function __construct() {
    $this->_scriptAddedFlags = [];
    $this->_fields = [];
    $this->_jsFilesNeeded = [];
    $this->_loadedScriptsList = [];
    $this->_validationJsFilesNeeded = ScriptFilePriorityManager::validationScriptFile();
  }

  private static function generateBfGlobalObjJS($contentIds = []) {
    // ["bitforms_3_submit_85_1", "bitforms_3_submit_85_2"]
    // bf_globals.{contentId}.inits
    $contentidArray = json_encode($contentIds);
    return <<<GLOBALOBJ
    if(!window.bf_globals){ window.bf_globals = {};}
    $contentidArray.forEach(function(contentId){
      if(!window.bf_globals[contentId]){
        window.bf_globals[contentId] = {inits: {}, contentId: contentId};
      }else{ 
        window.bf_globals[contentId].inits = {};
        window.bf_globals[contentId].contentId = contentId;
      }
    });
GLOBALOBJ;
  }

  private static function isValidationNeeded($fldData) {
    $validationsToCheck = ['valid->req', 'valid->regexr', 'mn', 'mx',  'opt', 'err->invalid->show'];
    foreach ($validationsToCheck as $property) {
      $needValidation = Helpers::property_exists_nested($fldData, $property);
      if ($needValidation) {
        return true;
      }
    }
    return false;
  }

  public function generateJsFile($formContents, $fields, $contentIds, $postId, $formIDs = null, $preview = false) {
    add_option('bitforms_frontend_js_generating', true);
    $this->_formContents = $formContents;
    $this->_fields = $fields;

    $this->appendJs(self::generateBfGlobalObjJS($contentIds), $postId, $preview, 'w');
    $this->_jsFilesNeeded = ScriptFilePriorityManager::jsFile();

    // Recaptcha v3 script is loaded separately
    $this->appendJs($this->getRecaptchaV3Script($formIDs), $postId, $preview);

    // helper js files for whole form
    foreach ($this->_jsFilesNeeded['helperScript'] as $jsFile) {
      $this->addScriptInLoadedScriptsList($jsFile);
    }

    // for add validation js files
    $this->jsValidationNeededFile();

    // js files for all fields
    $this->jsFieldsNeededFile();

    // for frontend helper js files
    $this->jsFrontendScript();

    // for hidden Field when catch plugin on
    $this->jsHiddenFieldScript();

    //⚠👆 every script file generate method call before this method
    $this->appendJs($this->getScript(), $postId, $preview);

    // for js file minification
    $this->appendJs(self::getCustomJsCodes($contentIds), $postId, $preview);
    delete_option('bitforms_frontend_js_generating');
    return true;
  }

/*
  public function generateJsFile($formContents, $fields, $contentIds, $postId, $formIDs = null, $preview = false) {
    $this->_formContents = $formContents;
    $this->_fields = $fields;

    $script = '';
    $script .= self::generateBfGlobalObjJS($contentIds);
    $this->_jsFilesNeeded = ScriptFilePriorityManager::jsFile();

    // Recaptcha v3 script is loaded separately
    $script .= $this->getRecaptchaV3Script($formIDs);

    // custom js files for whole form
    foreach ($this->_jsFilesNeeded['helperScript'] as $jsFile) {
      $this->addScriptInLoadedScriptsList($jsFile);
    }

    // for add validation js files
    $this->jsValidationNeededFile();

    // js files for all fields
    $this->jsFieldsNeededFile();

    // for frontend helper js files
    $this->jsFrontendScript();

    // for hidden Field when catch plugin on
    $this->jsHiddenFieldScript();

    //⚠👆 every script file generate method call before this method
    $script .= $this->getScript();

    // for js file minification
    $script = Helpers::minifyJS($script);

    $script .= self::getCustomJsCodes($contentIds);

    // write script file
    $fileName = '';
    $path = '';
    if ($preview) {
      $fileName = "preview-{$postId}.js";
      $path = 'form-scripts';
    } else {
      $fileName = "bitform-js-$postId.js";
      $path = "form-scripts/{$postId}";
    }
    Helpers::saveFile($path, $fileName, $script, 'w');
    return true;
  }
*/
  private function appendJs($script, $postId, $preview, $mode = 'a') {
    $fileName = '';
    $path = '';
    if ($preview) {
      $fileName = "preview-{$postId}.js";
      $path = 'form-scripts';
    } else {
      $fileName = "bitform-js-$postId.js";
      $path = "form-scripts/{$postId}";
    }
    Helpers::saveFile($path, $fileName,  Helpers::minifyJS($script), $mode);
  }

  private function getRecaptchaV3Script($formIds) {
    foreach ($formIds as $formID) {
      if (in_array('RecaptchaV3', $this->_scriptAddedFlags)) {
        break;
      }
      $getCaptchaV3Settings = (new FormManager($formID))->getCaptchaV3Settings();
      if ($getCaptchaV3Settings) {
        $integrationHandler = new IntegrationHandler(0);
        $allFormIntegrations = $integrationHandler->getAllIntegration('app', 'gReCaptchaV3');
        $siteKey = json_decode($allFormIntegrations[0]->integration_details)->siteKey;
        $this->_scriptAddedFlags[] = 'RecaptchaV3';
        return RecaptchaV3::init($siteKey);
      }
    }
  }

  private function getScript() {
    usort($this->_loadedScriptsList, function ($a, $b) {
      return $a['priority'] - $b['priority'];
    });

    $script = '';
    foreach ($this->_loadedScriptsList as $scriptFileArr) {
      $fileNam = $scriptFileArr['filename'];
      if (!isset($scriptFileArr['scriptTyp']) || 'script' === $scriptFileArr['scriptTyp']) {
        if (self::getFileFromAssetsJs($fileNam)) {
          $script .= self::getFileFromAssetsJs($fileNam);
          continue;
        }
        continue;
      }
      if ('init' === $scriptFileArr['scriptTyp']) {
        $fieldObjInstance = $scriptFileArr['source'] . $fileNam;
        if (!class_exists($fieldObjInstance)) {
          continue;
        } // when class not found, skip load script
        $encodedConf = json_encode($scriptFileArr['field']->fldConfigs);
        $script .= $fieldObjInstance::init($scriptFileArr['fk'], $encodedConf, $scriptFileArr['contentId']);
        continue;
      }
      if ('custom' === $scriptFileArr['scriptTyp']) {
        $fileInstance = $scriptFileArr['source'] . $fileNam;
        if (!class_exists($fileInstance)) {
          continue;
        } // when class not found, skip load script
        $script .= $fileInstance::init($scriptFileArr['fk'], $scriptFileArr['field'], $scriptFileArr['contentId']);
      }
    }
    return $script;
  }

  private function jsValidationNeededFile() {
    foreach ($this->_fields as $flds) {
      foreach ($flds as $fld) {
        $fldData = $fld['field'];
        // for validation js files
        if (self::isValidationNeeded($fldData)) {
          $validation = $this->_validationJsFilesNeeded['validation'];
          $this->addScriptInLoadedScriptsList($validation);
        }
        // for required
        if (Helpers::property_exists_nested($fldData, 'valid->req')) {
          $fileArr = $this->_validationJsFilesNeeded['requiredFldValidation'];
          $this->addScriptInLoadedScriptsList($fileArr);
        }
        // for regex
        if (Helpers::property_exists_nested($fldData, 'valid->regexr')) {
          $patternFile = $this->_validationJsFilesNeeded['generateBackslashPattern'];
          $rgx = $this->_validationJsFilesNeeded['regexPatternValidation'];
          $this->addScriptInLoadedScriptsList($patternFile);
          $this->addScriptInLoadedScriptsList($rgx);
        }

        $validationScriptFileMapping = ScriptFilePriorityManager::validationScriptFileMapping($fldData->typ);
        if ($validationScriptFileMapping) {
          foreach ($validationScriptFileMapping as $key => $value) {
            foreach ($value['paths'] as $path) {
              if (Helpers::property_exists_nested($fldData, $path)) {
                $file = $this->_validationJsFilesNeeded[$key];
                $this->addScriptInLoadedScriptsList($file);
              }
            }
            if (isset($value['dependencies'])) {
              foreach ($value['dependencies'] as $dependency) {
                $dependencyFile = $this->_validationJsFilesNeeded[$dependency];
                $this->addScriptInLoadedScriptsList($dependencyFile);
              }
            }
          }
        }
      }
    }
  }

  private function jsFieldsNeededFile() {
    foreach ($this->_fields as $typ => $flds) {
      if (!array_key_exists($typ, $this->_jsFilesNeeded)) {
        continue;
      }
      $fldScriptArr = $this->_jsFilesNeeded[$typ];

      foreach ($flds as $fld) {
        if ('advanced-file-up' === $typ) {
          $configs = $fld['field']->config;
          foreach ($configs as $configKey => $config) {
            if ($configs->$configKey) {
              $filepondPlugin = ScriptFilePriorityManager::filePondPlugins($configKey);
              if ($filepondPlugin) {
                $this->addScriptInLoadedScriptsList($filepondPlugin);
              }
            }
          }
        }
        foreach ($fldScriptArr as $scriptFile) {
          if (!isset($scriptFile['scriptTyp'])) {
            $this->addScriptInLoadedScriptsList($scriptFile);
            continue;
          }
          if ('init' === $scriptFile['scriptTyp']) {
            $scriptFile['field'] = $fld['field'];
            $scriptFile['fk'] = $fld['fk'];
            $scriptFile['formID'] = $fld['formID'];
            $scriptFile['contentId'] = $fld['contentId'];
            $fld['field']->fldConfigs = self::generateFieldConfig($fld['fk'], $fld['field'], $fld['formID']);
            $this->_loadedScriptsList[] = $scriptFile;
            continue;
          }
          if ('custom' === $scriptFile['scriptTyp']) {
            $scriptFile['field'] = $fld['field'];
            $scriptFile['fk'] = $fld['fk'];
            $scriptFile['contentId'] = $fld['contentId'];
            $this->addScriptInLoadedScriptsList($scriptFile);
          }
        }
      }
    }
  }

  private static function getCustomJsCodes($contentIds = []) {
    $script = 'let bfContentId = "", bfVars= "";';
    foreach ($contentIds as $contentId) {
      $jsCode = self::getCustomCodes(explode('_', $contentId)[1])['JavaScript'];
      if (!empty($jsCode)) {
        $script .= " bfContentId = '{$contentId}'; bfVars = window.bf_globals.{$contentId}.smartTags; {$jsCode}";
      }
    }

    return $script;
  }

  private static function getFileFromAssetsJs($fileName) {
    $sourceJsFile = BITFORMS_PLUGIN_DIR_PATH . 'assets' . DIRECTORY_SEPARATOR . $fileName;
    if (file_exists($sourceJsFile)) {
      return file_get_contents($sourceJsFile);
    }
    Log::debug_log('file not found: ' . $fileName);
    return false;
  }

  public static function saveCssFile($formId, $atomicCssText) {
    $path = 'form-styles';
    $fileName = "bitform-$formId.css";
    if (!isset($formId) || '' === $formId) {
      return new WP_Error('missing_form_id', __('Error Occurred, Please Reload', 'bit-form'));
    }
    return Helpers::saveFile($path, $fileName, $atomicCssText, 'w');
  }

  public static function customCodeFile($formId, $customCodes) {
    // for js file
    $path = 'form-scripts';
    $fileName = "bitform-custom-$formId.js";
    self::customCodeFileSaveOrDelete($customCodes->JavaScript, $path, $fileName);

    // for css file
    $path = 'form-styles';
    $fileName = "bitform-custom-$formId.css";
    self::customCodeFileSaveOrDelete($customCodes->CSS, $path, $fileName);

    return true;
  }

  private static function customCodeFileSaveOrDelete($script, $path, $fileName) {
    if ($script) {
      Helpers::saveFile($path, $fileName, $script, 'w');
    } else {
      $uploadPath = "$path/$fileName";
      $uploadFilePath = Helpers::generatePathDirOrFile($uploadPath);
      if (file_exists($uploadFilePath)) {
        unlink($uploadFilePath);
      }
    }
    return true;
  }

  public static function getCustomCodes($formId) {
    $customCodes = ['JavaScript' => '', 'CSS' => ''];
    $customJsPath = Helpers::generatePathDirOrFile("form-scripts/bitform-custom-$formId.js");
    $customCodes['JavaScript'] = Helpers::fileRead($customJsPath);

    $customCSSPath = Helpers::generatePathDirOrFile("form-styles/bitform-custom-$formId.css");
    $customCodes['CSS'] = Helpers::fileRead($customCSSPath);

    return $customCodes;
  }

  public static function generateFieldConfig($fieldKey, $field, $formID) {
    $fieldType = $field->typ;
    $missingConfigs = ScriptFilePriorityManager::fieldMissingConfigsProps($fieldType, $field) ?: [];
    $hasConfigProp = in_array('config', $missingConfigs);
    $fldConf = (object) [];
    if (false === $hasConfigProp && isset($field->config)) {
      $fldConf = $field->config;
    }
    $vars = ['fieldKey' => $fieldKey, 'formID' => $formID];
    foreach ($missingConfigs as $confPath => $fldPath) {
      $value = '';
      if (isset($fldPath['var']) && $vars[$fldPath['var']]) {
        $value = $vars[$fldPath['var']];
      }
      if (empty($value) && isset($fldPath['path'])) {
        $value = Helpers::getDataFromNestedPath($field, $fldPath['path']);
      }
      if (empty($value) && isset($fldPath['val'])) {
        $value = $fldPath['val'];
      }
      $fldConf = Helpers::setDataToNestedPath($fldConf, $confPath, $value);
    }
    return $fldConf;
  }

  private function getJsFuncForValidation() {
    $validationCmnFunc = ScriptFilePriorityManager::validationCommonFunction();
    foreach ($validationCmnFunc as $funcName => $funcArr) {
      // get need validation function from validationScriptFile()
      $scriptFile = $this->_validationJsFilesNeeded[$funcName];
      if (isset($funcArr['notFields'])) {
        if (is_array($funcArr['notFields'])) {
          foreach ($funcArr['notFields'] as $notField) {
            if (!isset($this->_fields[$notField])) {
              $this->addScriptInLoadedScriptsList($scriptFile);
            }
          }
        }
      }
      if (isset($funcArr['fields'])) {
        if (is_array($funcArr['fields'])) {
          foreach ($funcArr['fields'] as $fieldType) {
            if (isset($this->_fields[$fieldType])) {
              // for set function array in $this->_loadedScriptsList
              $this->addScriptInLoadedScriptsList($scriptFile);
            }
          }
        } else {
          // for all field types
          $this->addScriptInLoadedScriptsList($scriptFile);
        }
      }

      if (isset($funcArr['dependencies'])) {
        foreach ($funcArr['dependencies'] as $dependency) {
          $this->addScriptInLoadedScriptsList($dependency);
        }
      }
    }
  }

  private function addScriptInLoadedScriptsList($fileArr) {
    $fileName = $fileArr['filename'];
    if (!in_array($fileName, $this->_scriptAddedFlags)) {
      $this->_loadedScriptsList[] = $fileArr;
      $this->_scriptAddedFlags[] = $fileName;
    }
    return true;
  }

  private function jsFrontendScript() {
    foreach ($this->_formContents as $formContent) {
      if (Helpers::property_exists_nested($formContent, 'workFlowExist->oninput', true)) {
        $fileArr = ScriptFilePriorityManager::validationScriptFile()['conditionalLogic'];
        $this->addScriptInLoadedScriptsList($fileArr);
        $fileArr = ScriptFilePriorityManager::validationScriptFile()['validateFocusLost'];
        $this->addScriptInLoadedScriptsList($fileArr);
        $fileArr = ScriptFilePriorityManager::frontendScriptFile()['observeElm'];
        $this->addScriptInLoadedScriptsList($fileArr);
      }
      if (Helpers::property_exists_nested($formContent, 'additional->enabled->validateFocusLost', true)) {
        $fileArr = ScriptFilePriorityManager::validationScriptFile()['validateFocusLost'];
        $this->addScriptInLoadedScriptsList($fileArr);
      }
    }
  }

  private function jsHiddenFieldScript() {
    $appConfig = get_option('bitform_app_config');
    if (Helpers::property_exists_nested($appConfig, 'cache_plugin', true)) {
      $fileArr = ScriptFilePriorityManager::frontendScriptFile()['hidden-token-field'];
      $this->addScriptInLoadedScriptsList($fileArr);
      return;
    }
  }

  public function dd($data, $exit = false) {
    echo '+++++++++++++';
    echo '<pre>';
    var_dump($data);
    echo '</pre>';
    echo '+++++++++++++';
    $exit ? exit : '';
  }
}

```
