Overview

Namespaces

  • None
  • Quform
    • Traduttore_Registry

Classes

  • Quform
  • Quform_Admin_InsertForm
  • Quform_Admin_Page
  • Quform_Admin_Page_Controller
  • Quform_Admin_Page_Dashboard
  • Quform_Admin_Page_Entries
  • Quform_Admin_Page_Entries_Edit
  • Quform_Admin_Page_Entries_List
  • Quform_Admin_Page_Entries_View
  • Quform_Admin_Page_Factory
  • Quform_Admin_Page_Forms_Add
  • Quform_Admin_Page_Forms_Edit
  • Quform_Admin_Page_Forms_List
  • Quform_Admin_Page_Help
  • Quform_Admin_Page_Preview
  • Quform_Admin_Page_Settings
  • Quform_Admin_Page_Tools
  • Quform_Admin_Page_Tools_ExportEntries
  • Quform_Admin_Page_Tools_ExportForm
  • Quform_Admin_Page_Tools_Home
  • Quform_Admin_Page_Tools_ImportForm
  • Quform_Admin_Page_Tools_Migrate
  • Quform_Admin_Page_Tools_Uninstall
  • Quform_Api
  • Quform_Block
  • Quform_Builder
  • Quform_Captcha
  • Quform_ClassLoader
  • Quform_Confirmation
  • Quform_Container
  • Quform_Dashboard_Widget
  • Quform_Dispatcher
  • Quform_Element
  • Quform_Element_Captcha
  • Quform_Element_Checkbox
  • Quform_Element_Column
  • Quform_Element_Container
  • Quform_Element_Container_Iterator
  • Quform_Element_Date
  • Quform_Element_Email
  • Quform_Element_Factory
  • Quform_Element_Field
  • Quform_Element_File
  • Quform_Element_Group
  • Quform_Element_Hidden
  • Quform_Element_Honeypot
  • Quform_Element_Html
  • Quform_Element_Multi
  • Quform_Element_Multiselect
  • Quform_Element_Name
  • Quform_Element_Page
  • Quform_Element_Password
  • Quform_Element_Radio
  • Quform_Element_Recaptcha
  • Quform_Element_Row
  • Quform_Element_Select
  • Quform_Element_Submit
  • Quform_Element_Text
  • Quform_Element_Textarea
  • Quform_Element_Time
  • Quform_Entry_Controller
  • Quform_Entry_Exporter
  • Quform_Entry_List_Settings
  • Quform_Entry_List_Table
  • Quform_Entry_Processor
  • Quform_Entry_UserSearcher
  • Quform_Filter_Abstract
  • Quform_Filter_Alpha
  • Quform_Filter_AlphaNumeric
  • Quform_Filter_Digits
  • Quform_Filter_Regex
  • Quform_Filter_Static
  • Quform_Filter_StripTags
  • Quform_Filter_Trim
  • Quform_Form
  • Quform_Form_Controller
  • Quform_Form_Exporter
  • Quform_Form_Factory
  • Quform_Form_Importer
  • Quform_Form_Iterator
  • Quform_Form_List_Settings
  • Quform_Form_List_Table
  • Quform_Form_Processor
  • Quform_License
  • Quform_Migrator
  • Quform_NonceRefresher
  • Quform_Notification
  • Quform_Notification_Resender
  • Quform_Options
  • Quform_Permissions
  • Quform_Repository
  • Quform_ScriptLoader
  • Quform_Session
  • Quform_Settings
  • Quform_Shortcode
  • Quform_Themes
  • Quform_TokenReplacer
  • Quform_Toolbar
  • Quform_Translations
  • Quform_Updater
  • Quform_Upgrader
  • Quform_Uploader
  • Quform_Validator_Abstract
  • Quform_Validator_Alpha
  • Quform_Validator_AlphaNumeric
  • Quform_Validator_Array
  • Quform_Validator_Captcha
  • Quform_Validator_Date
  • Quform_Validator_Digits
  • Quform_Validator_Duplicate
  • Quform_Validator_Email
  • Quform_Validator_FileUpload
  • Quform_Validator_GreaterThan
  • Quform_Validator_Honeypot
  • Quform_Validator_Identical
  • Quform_Validator_InArray
  • Quform_Validator_Length
  • Quform_Validator_LessThan
  • Quform_Validator_Recaptcha
  • Quform_Validator_Regex
  • Quform_Validator_Required
  • Quform_Validator_Static
  • Quform_Validator_Time
  • Quform_View
  • Quform_ViewFactory
  • Quform_Widget_Form
  • Quform_Widget_Popup

Interfaces

  • Quform_Attachable
  • Quform_Element_Editable
  • Quform_Filter_Interface
  • Quform_Validator_Interface

Constants

  • Quform\Traduttore_Registry\TRANSIENT_KEY_PLUGIN
  • Quform\Traduttore_Registry\TRANSIENT_KEY_THEME

Functions

  • Quform\Traduttore_Registry\add_project
  • Quform\Traduttore_Registry\clean_translations_cache
  • Quform\Traduttore_Registry\get_available_locales
  • Quform\Traduttore_Registry\get_installed_translations
  • Quform\Traduttore_Registry\get_translations
  • Quform\Traduttore_Registry\register_clean_translations_cache
  • Quform\Traduttore_Registry\sanitize_date
  • Overview
  • Namespace
  • Class
   1: <?php
   2: 
   3: /**
   4:  * @copyright Copyright (c) 2009-2022 ThemeCatcher (https://www.themecatcher.net)
   5:  */
   6: class Quform_Form
   7: {
   8:     /**
   9:      * @var int
  10:      */
  11:     protected $id;
  12: 
  13:     /**
  14:      * The unique ID is unique to each form instance, even the same form on the same page
  15:      *
  16:      * @var string
  17:      */
  18:     protected $uniqueId;
  19: 
  20:     /**
  21:      * @var Quform_Element_Page[]
  22:      */
  23:     protected $pages = array();
  24: 
  25:     /**
  26:      * @var array
  27:      */
  28:     protected $config = array();
  29: 
  30:     /**
  31:      * Notifications to send
  32:      *
  33:      * @var Quform_Notification[]
  34:      */
  35:     protected $notifications = array();
  36: 
  37:     /**
  38:      * Confirmations
  39:      *
  40:      * @var Quform_Confirmation[]
  41:      */
  42:     protected $confirmations = array();
  43: 
  44:     /**
  45:      * The single confirmation to use for the submission
  46:      *
  47:      * @var Quform_Confirmation
  48:      */
  49:     protected $confirmation;
  50: 
  51:     /**
  52:      * @var Quform_TokenReplacer
  53:      */
  54:     protected $tokenReplacer;
  55: 
  56:     /**
  57:      * @var Quform_Options
  58:      */
  59:     protected $options;
  60: 
  61:     /**
  62:      * @var Quform_Session
  63:      */
  64:     protected $session;
  65: 
  66:     /**
  67:      * Is the form active?
  68:      *
  69:      * @var bool
  70:      */
  71:     protected $active = true;
  72: 
  73:     /**
  74:      * Has the form been successfully submitted?
  75:      *
  76:      * @var boolean
  77:      */
  78:     protected $submitted = false;
  79: 
  80:     /**
  81:      * The flag for showing the global form error message for non-Ajax forms
  82:      *
  83:      * @var boolean
  84:      */
  85:     protected $showGlobalError = false;
  86: 
  87:     /**
  88:      * Character encoding to use
  89:      *
  90:      * @var string
  91:      */
  92:     protected $charset = 'UTF-8';
  93: 
  94:     /**
  95:      * The dynamic values
  96:      *
  97:      * @var array
  98:      */
  99:     protected $dynamicValues = array();
 100: 
 101:     /**
 102:      * The current submitted entry ID
 103:      *
 104:      * @var int|null
 105:      */
 106:     protected $entryId;
 107: 
 108:     /**
 109:      * The current page being viewed/processed
 110:      *
 111:      * @var Quform_Element_Page
 112:      */
 113:     protected $currentPage;
 114: 
 115:     /**
 116:      * @param  int                   $id
 117:      * @param  string                $uniqueId
 118:      * @param  Quform_Session        $session
 119:      * @param  Quform_TokenReplacer  $tokenReplacer
 120:      * @param  Quform_Options        $options
 121:      */
 122:     public function __construct($id, $uniqueId, Quform_Session $session, Quform_TokenReplacer $tokenReplacer, Quform_Options $options)
 123:     {
 124:         $this->setId($id);
 125:         $this->setUniqueId($uniqueId);
 126:         $this->session = $session;
 127:         $this->tokenReplacer = $tokenReplacer;
 128:         $this->options = $options;
 129:     }
 130: 
 131:     /**
 132:      * Set the ID of the form
 133:      *
 134:      * @param int $id
 135:      */
 136:     public function setId($id)
 137:     {
 138:         $this->id = $id;
 139:     }
 140: 
 141:     /**
 142:      * Get the ID of the form
 143:      *
 144:      * @return int
 145:      */
 146:     public function getId()
 147:     {
 148:         return $this->id;
 149:     }
 150: 
 151:     /**
 152:      * Returns the config value for the given $key
 153:      *
 154:      * If the value is null, the default will be returned
 155:      *
 156:      * @param   string|null  $key      The config key
 157:      * @param   null|mixed   $default  The default value to return if the value key not exist
 158:      * @return  mixed                  The config value or $default if not set
 159:      */
 160:     public function config($key = null, $default = null)
 161:     {
 162:         $value = Quform::get($this->config, $key, $default);
 163: 
 164:         if ($value === null) {
 165:             $value = Quform::get(call_user_func(array(get_class($this), 'getDefaultConfig')), $key, $default);
 166:         }
 167: 
 168:         return $value;
 169:     }
 170: 
 171:     /**
 172:      * Set the config value for the given $key or multiple values using an array
 173:      *
 174:      * @param   string|array  $key    Key or array of key/values
 175:      * @param   mixed         $value  Value or null if $key is array
 176:      * @return  $this
 177:      */
 178:     public function setConfig($key, $value = null)
 179:     {
 180:         if (is_array($key)) {
 181:             foreach ($key as $k => $v) {
 182:                 $this->config[$k] = $v;
 183:             }
 184:         } else {
 185:             $this->config[$key] = $value;
 186:         }
 187: 
 188:         return $this;
 189:     }
 190: 
 191:     /**
 192:      * Render the form and return the HTML
 193:      *
 194:      * @param   array   $options         The options array
 195:      * @param   string  $outputOverride  Display this HTML instead of rendering the form
 196:      * @return  string
 197:      */
 198:     public function render(array $options = array(), $outputOverride = '')
 199:     {
 200:         $outputOverride = apply_filters('quform_form_output_override', $outputOverride, $this);
 201:         $outputOverride = apply_filters('quform_form_output_override_' . $this->getId(), $outputOverride, $this);
 202: 
 203:         if (Quform::isNonEmptyString($outputOverride)) {
 204:             return $outputOverride;
 205:         }
 206: 
 207:         $options = wp_parse_args($options, array(
 208:             'show_title' => true,
 209:             'show_description' => true
 210:         ));
 211: 
 212:         ob_start();
 213:         do_action('quform_pre_display', $this);
 214:         do_action('quform_pre_display_' . $this->getId(), $this);
 215:         $output = ob_get_clean();
 216: 
 217:         $output .= sprintf('<div id="quform-%s" class="%s">', Quform::escape($this->getUniqueId()), Quform::escape(Quform::sanitizeClass($this->getContainerClasses())));
 218: 
 219:         $formAttributes = array(
 220:             'id' => sprintf('quform-form-%s', $this->getUniqueId()),
 221:             'class' => sprintf('quform-form quform-form-%d', $this->getId()),
 222:             'action' => $this->getAction(),
 223:             'method' => 'post',
 224:             'enctype' => 'multipart/form-data',
 225:             'novalidate' => 'novalidate',
 226:             'data-options' => $this->getJsConfig()
 227:         );
 228: 
 229:         $formAttributes = apply_filters('quform_form_attributes', $formAttributes, $this);
 230:         $formAttributes = apply_filters('quform_form_attributes_' . $this->getId(), $formAttributes, $this);
 231: 
 232:         $output .= sprintf('<form%s>', Quform::parseHtmlAttributes($formAttributes));
 233: 
 234:         if (!apply_filters('quform_remove_hidden_submit_button', false)) {
 235:             $output .= '<button class="quform-default-submit" name="quform_submit" type="submit" value="submit" aria-hidden="true" tabindex="-1"></button>';
 236:         }
 237: 
 238:         $output .= sprintf('<div class="quform-form-inner quform-form-inner-%d">', Quform::escape($this->getId()));
 239: 
 240:         $output .= $this->getHiddenInputHtml();
 241: 
 242:         $output .= $this->getTitleDescriptionHtml($options['show_title'], $options['show_description']);
 243: 
 244:         $output .= $this->getSuccessMessageHtml('above');
 245: 
 246:         $output .= sprintf('<div class="%s">', Quform::escape(Quform::sanitizeClass($this->getElementsClasses())));
 247: 
 248:         $output .= $this->getPageProgressHtml();
 249: 
 250:         $output .= $this->getGlobalErrorHtml();
 251: 
 252:         foreach ($this->pages as $page) {
 253:             $output .= $page->render($this->getContext());
 254:         }
 255: 
 256:         $output .= '</div>';
 257: 
 258:         $output .= $this->getReferralLinkHtml();
 259: 
 260:         $output .= $this->getUploadProgressHtml();
 261: 
 262:         $output .= $this->getSuccessMessageHtml('below');
 263: 
 264:         $output .= $this->getLoadingHtml();
 265: 
 266:         $output .= '</div>';
 267: 
 268:         $output .= $this->getEditFormLinkHtml();
 269: 
 270:         $output .= '</form></div>';
 271: 
 272:         return $output;
 273:     }
 274: 
 275:     /**
 276:      * Render a popup form
 277:      *
 278:      * @param   array   $options         The options array
 279:      * @param   string  $outputOverride  Display this HTML instead of rendering the form
 280:      * @return  string
 281:      */
 282:     public function renderPopup(array $options = array(), $outputOverride = '')
 283:     {
 284:         $options = wp_parse_args($options, array(
 285:             'content' => '',
 286:             'options' => '',
 287:             'width' => '',
 288:             'show_title' => true,
 289:             'show_description' => true
 290:         ));
 291: 
 292:         if (Quform::isNonEmptyString($options['options'])) {
 293:             $options['options'] = json_decode($options['options'], true);
 294:         }
 295: 
 296:         if ( ! is_array($options['options'])) {
 297:             $options['options'] = array();
 298:         }
 299: 
 300:         if (Quform::isNonEmptyString($options['width'])) {
 301:             $options['options']['width'] = $options['width'];
 302:         }
 303: 
 304:         $classes = array('quform-popup-link', 'quform-popup-link-' . $this->getId());
 305: 
 306:         $attributes = array(
 307:             'class' => join(' ', $classes),
 308:             'data-unique-id' => $this->getUniqueId()
 309:         );
 310: 
 311:         if ( ! empty($options['options'])) {
 312:             $attributes['data-options'] = wp_json_encode($options['options']);
 313:         }
 314: 
 315:         ob_start();
 316:         do_action('quform_pre_display_popup', $this);
 317:         do_action('quform_pre_display_popup_' . $this->getId(), $this);
 318:         $output = ob_get_clean();
 319: 
 320:         $output .= Quform::getHtmlTag('span', $attributes, do_shortcode($options['content']));
 321: 
 322:         $output .= '<div class="quform-popup">';
 323: 
 324:         $output .= $this->render($options, $outputOverride);
 325: 
 326:         $output .= '</div>';
 327: 
 328:         return $output;
 329:     }
 330: 
 331:     /**
 332:      * Get the HTML for the title and description
 333:      *
 334:      * @param   bool    $showTitle
 335:      * @param   bool    $showDescription
 336:      * @return  string
 337:      */
 338:     protected function getTitleDescriptionHtml($showTitle = true, $showDescription = true)
 339:     {
 340:         $output = '';
 341:         $title = $this->config('title');
 342:         $description = $this->config('description');
 343:         $showTitle = Quform::isNonEmptyString($title) && $showTitle;
 344:         $showDescription = Quform::isNonEmptyString($description) && $showDescription;
 345: 
 346:         if ($showTitle || $showDescription) {
 347:             $output .= '<div class="quform-form-title-description">';
 348: 
 349:             if ($showTitle) {
 350:                 $output .= Quform::getHtmlTag($this->config('titleTag'), array('class' => 'quform-form-title'), do_shortcode($title));
 351:             }
 352: 
 353:             if ($showDescription) {
 354:                 $output .= Quform::getHtmlTag('p', array('class' => 'quform-form-description'), do_shortcode($description));
 355:             }
 356: 
 357:             $output .= '</div>';
 358:         }
 359: 
 360:         return $output;
 361:     }
 362: 
 363:     /**
 364:      * Get the classes for the outermost wrapper
 365:      *
 366:      * @return array
 367:      */
 368:     protected function getContainerClasses()
 369:     {
 370:         $classes = array('quform', sprintf('quform-%d', $this->getId()));
 371: 
 372:         if (Quform::isNonEmptyString($this->config('theme'))) {
 373:             $classes[] = sprintf('quform-theme-%s', $this->config('theme'));
 374:         }
 375: 
 376:         if (Quform::isNonEmptyString($this->config('width')) && Quform::isNonEmptyString($this->config('position'))) {
 377:             $classes[] = sprintf('quform-position-%s', $this->config('position'));
 378:         }
 379: 
 380:         if ($this->isRtl()) {
 381:             $classes[] = 'quform-rtl';
 382:         }
 383: 
 384:         if ($this->options->get('preventFouc')) {
 385:             $classes[] = 'quform-prevent-fouc';
 386:         }
 387: 
 388:         if ($this->options->get('supportPageCaching') && ! Quform::isPostRequest()) {
 389:             $classes[] = 'quform-support-page-caching';
 390:         }
 391: 
 392:         if ( ! $this->config('ajax')) {
 393:             $classes[] = 'quform-no-ajax';
 394:         }
 395: 
 396:         if ($this->hasPages()) {
 397:             if ($this->getCurrentPage()->getId() === $this->getFirstPage()->getId()) {
 398:                 $classes[] = 'quform-is-first-page';
 399:             } elseif ($this->getCurrentPage()->getId() === $this->getLastPage()->getId()) {
 400:                 $classes[] = 'quform-is-last-page';
 401:             }
 402:         }
 403: 
 404:         if (Quform::isNonEmptyString($this->config('errorsPosition'))) {
 405:             $classes[] = sprintf('quform-errors-%s', $this->config('errorsPosition'));
 406:         }
 407: 
 408:         $classes = apply_filters('quform_form_container_classes', $classes, $this);
 409:         $classes = apply_filters('quform_form_container_classes_' . $this->getId(), $classes, $this);
 410: 
 411:         return $classes;
 412:     }
 413: 
 414:     /**
 415:      * Is the form RTL?
 416:      *
 417:      * @return bool
 418:      */
 419:     public function isRtl()
 420:     {
 421:         if ($this->config('rtl') == 'enabled') {
 422:             return true;
 423:         }
 424: 
 425:         if ($this->config('rtl') == 'global') {
 426:             return $this->options->get('rtl') == 'enabled' || ($this->options->get('rtl') === '' && is_rtl());
 427:         }
 428: 
 429:         return false;
 430:     }
 431: 
 432:     /**
 433:      * Get the locale for this form
 434:      *
 435:      * @return string
 436:      */
 437:     public function getLocale()
 438:     {
 439:         $locale = $this->config('locale');
 440: 
 441:         if (Quform::isNonEmptyString($locale)) {
 442:             $locale = apply_filters('quform_form_locale', $locale, $this);
 443:             $locale = apply_filters('quform_form_locale_' . $this->getId(), $locale, $this);
 444: 
 445:             return $locale;
 446:         }
 447: 
 448:         return $this->options->getLocale();
 449:     }
 450: 
 451:     /**
 452:      * Get the date format for PHP
 453:      *
 454:      * @return string
 455:      */
 456:     public function getDateFormat()
 457:     {
 458:         return Quform::isNonEmptyString($this->config('dateFormat')) ? $this->config('dateFormat') : $this->options->get('dateFormat');
 459:     }
 460: 
 461:     /**
 462:      * Get the date format for JavaScript
 463:      *
 464:      * @return string
 465:      */
 466:     public function getDateFormatJs()
 467:     {
 468:         return Quform::isNonEmptyString($this->config('dateFormatJs')) ? $this->config('dateFormatJs') : $this->options->get('dateFormatJs');
 469:     }
 470: 
 471:     /**
 472:      * Get the time format for PHP
 473:      *
 474:      * @return string
 475:      */
 476:     public function getTimeFormat()
 477:     {
 478:         return Quform::isNonEmptyString($this->config('timeFormat')) ? $this->config('timeFormat') : $this->options->get('timeFormat');
 479:     }
 480: 
 481:     /**
 482:      * Get the time format for JavaScript
 483:      *
 484:      * @return string
 485:      */
 486:     public function getTimeFormatJs()
 487:     {
 488:         return Quform::isNonEmptyString($this->config('timeFormatJs')) ? $this->config('timeFormatJs') : $this->options->get('timeFormatJs');
 489:     }
 490: 
 491:     /**
 492:      * Get the datetime format for PHP
 493:      *
 494:      * @return string
 495:      */
 496:     public function getDateTimeFormat()
 497:     {
 498:         return Quform::isNonEmptyString($this->config('dateTimeFormat')) ? $this->config('dateTimeFormat') : $this->options->get('dateTimeFormat');
 499:     }
 500: 
 501:     /**
 502:      * Get the datetime format for JavaScript
 503:      *
 504:      * @return string
 505:      */
 506:     public function getDateTimeFormatJs()
 507:     {
 508:         return Quform::isNonEmptyString($this->config('dateTimeFormatJs')) ? $this->config('dateTimeFormatJs') : $this->options->get('dateTimeFormatJs');
 509:     }
 510: 
 511:     /**
 512:      * Get the classes for the elements wrapper div
 513:      *
 514:      * @return array
 515:      */
 516:     protected function getElementsClasses()
 517:     {
 518:         $classes = array(
 519:             'quform-elements',
 520:             sprintf('quform-elements-%d', $this->getId()),
 521:             'quform-cf'
 522:         );
 523: 
 524:         if (Quform::isNonEmptyString($this->config('responsiveElements')) && $this->config('responsiveElements') != 'custom') {
 525:             $classes[] = sprintf('quform-responsive-elements-%s', $this->config('responsiveElements'));
 526:         }
 527: 
 528:         if ($this->isSubmitted()) {
 529:             $confirmation = $this->getConfirmation();
 530: 
 531:             if ($confirmation instanceof Quform_Confirmation && $confirmation->config('hideForm')) {
 532:                 $classes[] = 'quform-hidden';
 533:             }
 534:         }
 535: 
 536:         return $classes;
 537:     }
 538: 
 539:     /**
 540:      * Get the action attribute for the &lt;form&gt;
 541:      *
 542:      * @return string
 543:      */
 544:     protected function getAction()
 545:     {
 546:         $useAnchor = apply_filters('quform_use_anchor', true);
 547:         $useAnchor = apply_filters("quform_use_anchor_{$this->getId()}", $useAnchor);
 548: 
 549:         return add_query_arg(array()) . ($useAnchor ? "#quform-{$this->getUniqueId()}" : '');
 550:     }
 551: 
 552:     /**
 553:      * Get the HTML for the hidden inputs
 554:      *
 555:      * @return string
 556:      */
 557:     protected function getHiddenInputHtml()
 558:     {
 559:         $output = '';
 560: 
 561:         $inputs = array(
 562:             'quform_form_id' => $this->getId(),
 563:             'quform_form_uid' => $this->getUniqueId(),
 564:             'quform_count' => $this->config('count'),
 565:             'form_url' => Quform::getCurrentUrl(),
 566:             'referring_url' => Quform::getHttpReferer(),
 567:             'post_id' => Quform::getPostProperty('ID'),
 568:             'post_title' => Quform::getPostProperty('post_title'),
 569:             'quform_current_page_id' => $this->getCurrentPage()->getId(),
 570:             'quform_loaded' => Quform::getTimestampHash(),
 571:         );
 572: 
 573:         if ($this->options->get('csrfProtection')) {
 574:             $inputs['quform_csrf_token'] = $this->getCsrfToken();
 575:         }
 576: 
 577:         foreach ($inputs as $name => $value) {
 578:             $output .= sprintf('<input type="hidden" name="%s" value="%s" />', Quform::escape($name), Quform::escape($value));
 579:         }
 580: 
 581:         return $output;
 582:     }
 583: 
 584:     /**
 585:      * Get the context (inheritable settings) for passing to child elements when rendering the form and generating CSS
 586:      *
 587:      * @return array
 588:      */
 589:     public function getContext()
 590:     {
 591:         return array(
 592:             'labelPosition' => $this->config('labelPosition'),
 593:             'labelWidth' => $this->config('labelWidth'),
 594:             'tooltipType' => $this->config('tooltipType'),
 595:             'tooltipEvent' => $this->config('tooltipEvent'),
 596:             'fieldSize' => $this->config('fieldSize'),
 597:             'fieldWidth' => $this->config('fieldWidth'),
 598:             'fieldWidthCustom' => $this->config('fieldWidthCustom'),
 599:             'buttonStyle' => $this->config('buttonStyle'),
 600:             'buttonSize' => $this->config('buttonSize'),
 601:             'buttonWidth' => $this->config('buttonWidth'),
 602:             'buttonWidthCustom' => $this->config('buttonWidthCustom'),
 603:             'responsiveColumns' => $this->config('responsiveColumns'),
 604:             'responsiveColumnsCustom' => $this->config('responsiveColumnsCustom'),
 605:             'optionsStyle' => $this->config('optionsStyle'),
 606:             'optionsButtonStyle' => $this->config('optionsButtonStyle'),
 607:             'optionsButtonSize' => $this->config('optionsButtonSize'),
 608:             'optionsButtonWidth' => $this->config('optionsButtonWidth'),
 609:             'optionsButtonWidthCustom' => $this->config('optionsButtonWidthCustom'),
 610:             'optionsButtonIconPosition' => $this->config('optionsButtonIconPosition')
 611:         );
 612:     }
 613: 
 614:     /**
 615:      * Get the HTML for the Quform referral link
 616:      *
 617:      * @return string
 618:      */
 619:     protected function getReferralLinkHtml()
 620:     {
 621:         $output = '';
 622: 
 623:         if ($this->options->get('referralEnabled') && Quform::isNonEmptyString($this->options->get('referralLink'))) {
 624:             $output .= '<div class="quform-referral-link">';
 625:             $output .= sprintf('<a href="%s">%s</a>', esc_url($this->options->get('referralLink')), $this->options->get('referralText'));
 626:             $output .= '</div>';
 627:         }
 628: 
 629:         return $output;
 630:     }
 631: 
 632:     /**
 633:      * Get the HTML for the file upload progress bar
 634:      *
 635:      * @return string
 636:      */
 637:     protected function getUploadProgressHtml()
 638:     {
 639:         $output = '';
 640: 
 641:         if ($this->hasEnhancedFileUploadElement()) {
 642:             $classes = array('quform-upload-progress-wrap');
 643: 
 644:             if (Quform::isNonEmptyString($this->config('loadingType')) &&
 645:                 $this->config('loadingOverlay') &&
 646:                 ($this->config('loadingPosition') == 'over-form' || $this->config('loadingPosition') == 'over-screen')
 647:             ) {
 648:                 $classes[] = sprintf('quform-loading-position-%s', $this->config('loadingPosition'));
 649:             }
 650: 
 651:             $output .= sprintf('<div class="%s">', Quform::escape(join(' ', $classes)));
 652:             $output .= '<div class="quform-upload-progress-bar-wrap"><div class="quform-upload-progress-bar"></div></div>';
 653:             $output .= '<div class="quform-upload-info quform-cf"><div class="quform-upload-filename"></div></div>';
 654:             $output .= '</div>';
 655:         }
 656: 
 657:         return $output;
 658:     }
 659: 
 660:     /**
 661:      * Get the HTML for the edit form link
 662:      *
 663:      * @return string
 664:      */
 665:     protected function getEditFormLinkHtml()
 666:     {
 667:         $output = '';
 668: 
 669:         if ($this->options->get('showEditLink') && $this->config('environment') != 'preview' && is_user_logged_in() && current_user_can('quform_edit_forms')) {
 670:             $output .= '<div class="quform-edit-form">';
 671: 
 672:             $editUrl = sprintf(admin_url('admin.php?page=quform.forms&sp=edit&id=%d'), $this->getId());
 673: 
 674:             $output .= sprintf('<a class="quform-edit-form-link" href="%s"><i class="qicon qicon-mode_edit"></i>%s</a>', esc_url($editUrl), esc_html__('Edit this form', 'quform'));
 675: 
 676:             $output .= '</div>';
 677:         }
 678: 
 679:         return $output;
 680:     }
 681: 
 682:     /**
 683:      * Add a form notification
 684:      *
 685:      * @param   Quform_Notification  $notification
 686:      * @return  Quform_Form
 687:      */
 688:     public function addNotification(Quform_Notification $notification)
 689:     {
 690:         $this->notifications[] = $notification;
 691: 
 692:         return $this;
 693:     }
 694: 
 695:     /**
 696:      * Get the form notifications
 697:      *
 698:      * @return Quform_Notification[]
 699:      */
 700:     public function getNotifications()
 701:     {
 702:         return $this->notifications;
 703:     }
 704: 
 705:     /**
 706:      * Get a notification by identifier
 707:      *
 708:      * @param   string  $identifier  The notification identifier (aka unique ID)
 709:      * @return  Quform_Notification|null
 710:      */
 711:     public function getNotification($identifier)
 712:     {
 713:         foreach ($this->getNotifications() as $notification) {
 714:             if ($notification->getIdentifier() == $identifier) {
 715:                 return $notification;
 716:             }
 717:         }
 718: 
 719:         return null;
 720:     }
 721: 
 722:     /**
 723:      * Replace the variables in the given string
 724:      *
 725:      * @param   string  $text
 726:      * @param   string  $format
 727:      * @return  string
 728:      */
 729:     public function replaceVariables($text, $format = 'text')
 730:     {
 731:         return $this->tokenReplacer->replaceVariables($text, $format, $this);
 732:     }
 733: 
 734:     /**
 735:      * Replace the variables in the given text before the form is processed
 736:      *
 737:      * @param   string  $text
 738:      * @param   string  $format
 739:      * @return  string
 740:      */
 741:     public function replaceVariablesPreProcess($text, $format = 'text')
 742:     {
 743:         return $this->tokenReplacer->replaceVariablesPreProcess($text, $format, $this);
 744:     }
 745: 
 746:     /**
 747:      * @return bool
 748:      */
 749:     public function isActive()
 750:     {
 751:         return $this->active;
 752:     }
 753: 
 754:     /**
 755:      * Set whether the form is active
 756:      *
 757:      * @param   boolean  $flag
 758:      * @return  Quform_Form
 759:      */
 760:     public function setIsActive($flag)
 761:     {
 762:         $this->active = $flag;
 763: 
 764:         return $this;
 765:     }
 766: 
 767:     /**
 768:      * Add a confirmation
 769:      *
 770:      * @param Quform_Confirmation $confirmation
 771:      */
 772:     public function addConfirmation(Quform_Confirmation $confirmation)
 773:     {
 774:         $this->confirmations[] = $confirmation;
 775:     }
 776: 
 777:     /**
 778:      * Set the confirmation to use for this submission
 779:      *
 780:      * If there is only one confirmation, it will be used, otherwise the first matching conditional logic
 781:      */
 782:     public function setConfirmation()
 783:     {
 784:         $this->confirmation = $this->confirmations[0];
 785:         $count = count($this->confirmations);
 786: 
 787:         if ($count > 1) {
 788:             for ($i = 1; $i < $count; $i++) {
 789:                 $confirmation = $this->confirmations[$i];
 790: 
 791:                 if ($confirmation->config('enabled') && count($confirmation->config('logicRules')) && $this->checkLogicAction($confirmation->config('logicAction'), $confirmation->config('logicMatch'), $confirmation->config('logicRules'))) {
 792:                     $this->confirmation = $confirmation;
 793:                     break;
 794:                 }
 795:             }
 796:         }
 797:     }
 798: 
 799:     /**
 800:      * Get the confirmation to use for this submission
 801:      *
 802:      * @return Quform_Confirmation
 803:      */
 804:     public function getConfirmation()
 805:     {
 806:         return $this->confirmation;
 807:     }
 808: 
 809:     /**
 810:      * Get the HTML for the success message
 811:      *
 812:      * @param   string  $position
 813:      * @return  string
 814:      */
 815:     public function getSuccessMessageHtml($position = 'above')
 816:     {
 817:         $confirmation = $this->getConfirmation();
 818:         $output = '';
 819: 
 820:         if ($this->isSubmitted() &&
 821:             $confirmation->config('messagePosition') == $position &&
 822:             Quform::isNonEmptyString($message = $confirmation->getMessage())
 823:         ) {
 824:             $hasIcon = Quform::isNonEmptyString($confirmation->config('messageIcon'));
 825: 
 826:             $output = sprintf(
 827:                 '<div class="quform-success-message quform-success-message-%s%s">',
 828:                 $this->getId(),
 829:                 $hasIcon ? ' quform-success-message-has-icon' : ''
 830:             );
 831: 
 832:             if ($hasIcon) {
 833:                 $output .= sprintf('<div class="quform-success-message-icon"><i class="%s"></i></div>', $confirmation->config('messageIcon'));
 834:             }
 835: 
 836:             $output .= sprintf('<div class="quform-success-message-content">%s</div>', $message);
 837: 
 838:             $output .= '</div>';
 839:         }
 840: 
 841:         return $output;
 842:     }
 843: 
 844:     /**
 845:      * Get the HTML for the page progress
 846:      *
 847:      * @return string
 848:      */
 849:     public function getPageProgressHtml()
 850:     {
 851:         $type = $this->config('pageProgressType');
 852: 
 853:         if ( ! $this->hasPages() || ! Quform::isNonEmptyString($type)) {
 854:             return '';
 855:         }
 856: 
 857:         $currentPage = $this->getCurrentPage();
 858:         $currentPageIndex = 1;
 859: 
 860:         foreach ($this->pages as $pages) {
 861:             if ($pages == $currentPage) {
 862:                 break;
 863:             }
 864:             $currentPageIndex++;
 865:         }
 866: 
 867:         $output = sprintf('<div class="quform-page-progress quform-page-progress-type-%s">', $type);
 868: 
 869:         if ($type == 'numbers' || $type == 'percentage') {
 870:             $percent = round(($currentPageIndex / $this->getPageCount()) * 100);
 871: 
 872:             $output .= sprintf('<div class="quform-page-progress-bar" style="width: %d%%;">', esc_attr($percent));
 873:             $output .= '<span class="quform-page-progress-text">';
 874: 
 875:             if ($type == 'numbers') {
 876:                 $output .= sprintf(
 877:                     /* translators: Page x of x, %1$s: the current page number, %2$s: the total number of pages */
 878:                     esc_html($this->getTranslation('pageProgressNumbersText', __('Page %1$s of %2$s', 'quform'))),
 879:                     sprintf('<span class="quform-page-progress-number">%s</span>', $currentPageIndex),
 880:                     $this->getPageCount()
 881:                 );
 882:             } else {
 883:                 $output .= sprintf(
 884:                     /* translators: page progress percentage, %s: the page progress percentage, %%: the percentage sign */
 885:                     esc_html__('%s%%', 'quform'),
 886:                     sprintf('<span class="quform-page-progress-percentage">%s</span>', $percent)
 887:                 );
 888:             }
 889: 
 890:             $output .= '</span>';
 891:             $output .= '</div>';
 892:         } else if ($type == 'tabs') {
 893:             $output .= sprintf('<div class="quform-page-progress-tabs quform-%d-pages quform-cf">', count($this->pages));
 894: 
 895:             foreach ($this->pages as $page) {
 896:                 $output .= sprintf(
 897:                     '<div class="quform-page-progress-tab%s" data-id="%d">%s</div>',
 898:                     $page == $this->currentPage ? ' quform-current-tab' : '',
 899:                     $page->getId(),
 900:                     esc_html($page->getLabel())
 901:                 );
 902:             }
 903: 
 904:             $output .= '</div>';
 905:         }
 906: 
 907:         $output .= '</div>';
 908: 
 909:         return $output;
 910:     }
 911: 
 912:     /**
 913:      * Get the HTML for the loading indicator
 914:      *
 915:      * @return string
 916:      */
 917:     protected function getLoadingHtml()
 918:     {
 919:         if ( ! Quform::isNonEmptyString($this->config('loadingType')) ||
 920:             ($this->config('loadingPosition') != 'over-form' && $this->config('loadingPosition') != 'over-screen'))
 921:         {
 922:             return '';
 923:         }
 924: 
 925:         $classes = array(
 926:             'quform-loading',
 927:             sprintf('quform-loading-position-%s', $this->config('loadingPosition')),
 928:             sprintf('quform-loading-type-%s', $this->config('loadingType'))
 929:         );
 930: 
 931:         $output = sprintf('<div class="%s">', esc_attr(join(' ', $classes)));
 932: 
 933:         if ($this->config('loadingOverlay')) {
 934:             $output .= '<div class="quform-loading-overlay"></div>';
 935:         }
 936: 
 937:         $output .= '<div class="quform-loading-inner">';
 938: 
 939:         if ($this->config('loadingType') == 'custom') {
 940:             $output .= do_shortcode($this->config('loadingCustom'));
 941:         } else {
 942:             $output .= '<div class="quform-loading-spinner"><div class="quform-loading-spinner-inner"></div></div>';
 943:         }
 944: 
 945:         $output .= '</div></div>';
 946: 
 947:         return $output;
 948:     }
 949: 
 950:     /**
 951:      * Set the unique form ID
 952:      *
 953:      * The unique ID is unique to each form instance, even the same form on the same page
 954:      *
 955:      * @param string $uniqueId
 956:      */
 957:     public function setUniqueId($uniqueId)
 958:     {
 959:         $this->uniqueId = $uniqueId;
 960:     }
 961: 
 962:     /**
 963:      * Get the unique form ID
 964:      */
 965:     public function getUniqueId()
 966:     {
 967:         return $this->uniqueId;
 968:     }
 969: 
 970:     /**
 971:      * Get the JavaScript configuration for the frontend
 972:      *
 973:      * @return string
 974:      */
 975:     public function getJsConfig()
 976:     {
 977:         $config = array(
 978:             'id' => $this->getId(),
 979:             'uniqueId' => $this->getUniqueId(),
 980:             'theme' => $this->config('theme'),
 981:             'ajax' => $this->config('ajax'),
 982:             'logic' => $this->getLogicConfig(),
 983:             'currentPageId' => $this->getCurrentPage()->getId(),
 984:             'errorsIcon' => $this->config('errorsIcon'),
 985:             'updateFancybox' => apply_filters('quform_update_fancybox', true, $this),
 986:             'hasPages' => $this->hasPages(),
 987:             'pages' => $this->getPageIds(),
 988:             'pageProgressType' => $this->config('pageProgressType'),
 989:             'tooltipsEnabled' => $this->config('tooltipsEnabled'),
 990:             'tooltipClasses' => $this->config('tooltipClasses'),
 991:             'tooltipMy' => $this->config('tooltipMy'),
 992:             'tooltipAt' => $this->config('tooltipAt'),
 993:             'isRtl' => $this->isRtl()
 994:         );
 995: 
 996:         if (is_numeric($this->options->get('scrollOffset'))) {
 997:             $config['scrollOffset'] = ((int) $this->options->get('scrollOffset')) * -1;
 998:         }
 999: 
1000:         if (is_numeric($this->options->get('scrollSpeed'))) {
1001:             $config['scrollSpeed'] = (int) $this->options->get('scrollSpeed');
1002:         }
1003: 
1004:         $config = apply_filters('quform_form_js_config', $config, $this);
1005:         $config = apply_filters('quform_form_js_config_' . $this->getId(), $config, $this);
1006: 
1007:         return wp_json_encode($config);
1008:     }
1009: 
1010:     /**
1011:      * Get the character encoding
1012:      *
1013:      * @return string
1014:      */
1015:     public function getCharset()
1016:     {
1017:         return $this->charset;
1018:     }
1019: 
1020:     /**
1021:      * Set the character encoding
1022:      *
1023:      * @param string $charset
1024:      */
1025:     public function setCharset($charset)
1026:     {
1027:         $this->charset = $charset;
1028:     }
1029: 
1030:     /**
1031:      * @return array
1032:      */
1033:     public function getPages()
1034:     {
1035:         return $this->pages;
1036:     }
1037: 
1038:     /**
1039:      * Add a page to the form
1040:      *
1041:      * @param Quform_Element_Page $page The page to add
1042:      */
1043:     public function addPage(Quform_Element_Page $page)
1044:     {
1045:         $this->pages[$page->getName()] = $page;
1046:     }
1047: 
1048:     /**
1049:      * Set the values for all form elements
1050:      *
1051:      * @param  array  $values          The values to set
1052:      * @param  bool   $setOthersEmpty  Set the value of elements that are not in $values to empty
1053:      */
1054:     public function setValues($values, $setOthersEmpty = false)
1055:     {
1056:         foreach ($this->getRecursiveIterator() as $element) {
1057:             if ( ! ($element instanceof Quform_Element_Field) || $element instanceof Quform_Element_File) {
1058:                 continue;
1059:             }
1060: 
1061:             if ( ! $element->isVisible()) {
1062:                 // For non-visible fields, set the default or the empty value if there is no default
1063:                 $element->setValue($element->hasDefaultValue() ? $element->getDefaultValue() : $element->getEmptyValue());
1064:             } else if (isset($values[$element->getName()])) {
1065:                 $element->setValue($values[$element->getName()]);
1066:             } else if ($setOthersEmpty) {
1067:                 $element->setValue($element->getEmptyValue());
1068:             }
1069:         }
1070:     }
1071: 
1072:     /**
1073:      * Is the form valid?
1074:      *
1075:      * @return array The first value is valid boolean, second is the first page instance that has an error
1076:      */
1077:     public function isValid()
1078:     {
1079:         $valid = true;
1080:         $firstErrorPage = null;
1081: 
1082:         foreach ($this->pages as $page) {
1083:             if ( ! $page->isValid()) {
1084:                 $valid = false;
1085: 
1086:                 if (is_null($firstErrorPage)) {
1087:                     $firstErrorPage = $page;
1088:                 }
1089:             }
1090:         }
1091: 
1092:         return array($valid, $firstErrorPage);
1093:     }
1094: 
1095:     /**
1096:      * Get the validation errors
1097:      *
1098:      * @return array
1099:      */
1100:     public function getErrors()
1101:     {
1102:         $errors = array();
1103: 
1104:         foreach ($this->getRecursiveIterator() as $element) {
1105:             if ( ! $element instanceof Quform_Element_Field) {
1106:                 continue;
1107:             }
1108: 
1109:             if ($element->hasError()) {
1110:                 foreach ($element->getErrorArray() as $identifier => $message) {
1111:                     $errors[$identifier] = $message;
1112:                 }
1113:             }
1114:         }
1115: 
1116:         return $errors;
1117:     }
1118: 
1119:     /**
1120:      * Set the flag to show the global form error message
1121:      *
1122:      * @param bool $flag
1123:      */
1124:     public function setShowGlobalError($flag)
1125:     {
1126:         $this->showGlobalError = $flag;
1127:     }
1128: 
1129:     /**
1130:      * Get the flag to show the global form error message
1131:      *
1132:      * @return bool
1133:      */
1134:     public function getShowGlobalError()
1135:     {
1136:         return $this->showGlobalError;
1137:     }
1138: 
1139:     /**
1140:      * Get the global error message data
1141:      *
1142:      * @return array
1143:      */
1144:     public function getGlobalError()
1145:     {
1146:         return array(
1147:             'enabled' => $this->config('errorEnabled'),
1148:             'title' => $this->config('errorTitle'),
1149:             'content' => $this->config('errorContent')
1150:         );
1151:     }
1152: 
1153:     /**
1154:      * Get the HTML for the global form error message if enabled
1155:      *
1156:      * @return string
1157:      */
1158:     protected function getGlobalErrorHtml()
1159:     {
1160:         $output = '';
1161: 
1162:         if ($this->getShowGlobalError() && Quform::isNonEmptyString($this->config('errorContent'))) {
1163:             $output .= '<div class="quform-error-message"><div class="quform-error-message-inner">';
1164: 
1165:             if (Quform::isNonEmptyString($this->config('errorTitle'))) {
1166:                 $output .= sprintf('<div class="quform-error-message-title">%s</div>', $this->config('errorTitle'));
1167:             }
1168: 
1169:             $output .= sprintf('<div class="quform-error-message-content">%s</div>', $this->config('errorContent'));
1170: 
1171: 
1172:             $output .= '</div></div>';
1173:         }
1174: 
1175:         return $output;
1176:     }
1177: 
1178:     /**
1179:      * Get the element with the given name
1180:      *
1181:      * Returns the element or null if it does not exist
1182:      *
1183:      * @param   string               $nameOrId
1184:      * @return  Quform_Element|null
1185:      */
1186:     public function getElement($nameOrId)
1187:     {
1188:         return is_numeric($nameOrId) ? $this->getElementById($nameOrId) : $this->getElementByName($nameOrId);
1189:     }
1190: 
1191:     /**
1192:      * Set the value of the element with the given name
1193:      *
1194:      * @param   string|int   $nameOrId
1195:      * @param   mixed        $value
1196:      * @return  Quform_Form
1197:      */
1198:     public function setValue($nameOrId, $value)
1199:     {
1200:         $element = $this->getElement($nameOrId);
1201: 
1202:         if ($element instanceof Quform_Element_Field) {
1203:             $element->setValue($value);
1204:         }
1205: 
1206:         return $this;
1207:     }
1208: 
1209:     /**
1210:      * Set the value of the element with the given name
1211:      *
1212:      * @param   string|int  $nameOrId
1213:      * @param   mixed       $value
1214:      * @return  $this
1215:      */
1216:     public function setValueFromStorage($nameOrId, $value)
1217:     {
1218:         $element = $this->getElement($nameOrId);
1219: 
1220:         if ($element instanceof Quform_Element_Field) {
1221:             $element->setValueFromStorage($value);
1222:         }
1223: 
1224:         return $this;
1225:     }
1226: 
1227:     /**
1228:      * Get the values of all fields
1229:      *
1230:      * @return array The values of all fields
1231:      */
1232:     public function getValues()
1233:     {
1234:         $values = array();
1235: 
1236:         foreach ($this->getRecursiveIterator() as $element) {
1237:             if ($element instanceof Quform_Element_Field) {
1238:                 $values[$element->getName()] = $element->getValue();
1239:             }
1240:         }
1241: 
1242:         return $values;
1243:     }
1244: 
1245:     /**
1246:      * Get the values of a single field
1247:      *
1248:      * @param   string|int  $nameOrId
1249:      * @return  mixed       The value of the given field or null
1250:      */
1251:     public function getValue($nameOrId)
1252:     {
1253:         $element = $this->getElement($nameOrId);
1254: 
1255:         return $element instanceof Quform_Element_Field ? $element->getValue() : null;
1256:     }
1257: 
1258:     /**
1259:      * Get the value of the element with the given name, formatted in HTML
1260:      *
1261:      * @param   string  $nameOrId  The unique element name
1262:      * @return  string             The formatted HTML
1263:      */
1264:     public function getValueHtml($nameOrId)
1265:     {
1266:         $element = $this->getElement($nameOrId);
1267: 
1268:         return $element instanceof Quform_Element_Field ? $element->getValueHtml() : '';
1269:     }
1270: 
1271:     /**
1272:      * Get the value of the element with the given name, formatted in plain text
1273:      *
1274:      * @param   string $nameOrId   The unique element name
1275:      * @param   string $separator  The separator for array types
1276:      * @return  string             The formatted plain text
1277:      */
1278:     public function getValueText($nameOrId, $separator = ', ')
1279:     {
1280:         $element = $this->getElement($nameOrId);
1281: 
1282:         return $element instanceof Quform_Element_Field ? $element->getValueText($separator) : '';
1283:     }
1284: 
1285:     /**
1286:      * Get the element with the given ID.
1287:      *
1288:      * Returns the element or null if no element was found.
1289:      *
1290:      * @param   int                  $id
1291:      * @return  Quform_Element|null
1292:      */
1293:     public function getElementById($id)
1294:     {
1295:         foreach ($this->getRecursiveIterator(RecursiveIteratorIterator::SELF_FIRST) as $element) {
1296:             if ($element->getId() == $id) {
1297:                 return $element;
1298:             }
1299:         }
1300: 
1301:         return null;
1302:     }
1303: 
1304:     /**
1305:      * Get the element with the given name.
1306:      *
1307:      * Returns the element or null if no element was found.
1308:      *
1309:      * @param   string               $name
1310:      * @return  Quform_Element|null
1311:      */
1312:     public function getElementByName($name)
1313:     {
1314:         foreach ($this->getRecursiveIterator(RecursiveIteratorIterator::SELF_FIRST) as $element) {
1315:             if ($element->getName() == $name) {
1316:                 return $element;
1317:             }
1318:         }
1319: 
1320:         return null;
1321:     }
1322: 
1323:     /**
1324:      * Get the conditional logic configuration array
1325:      *
1326:      * @return array
1327:      */
1328:     public function getLogicConfig()
1329:     {
1330:         $logic = array();
1331:         $dependents = array();
1332:         $elementIds = array();
1333:         $dependentElementIds = array();
1334: 
1335:         foreach ($this->getRecursiveIterator(RecursiveIteratorIterator::SELF_FIRST) as $element) {
1336:             if ($element->config('logicEnabled') && count($element->config('logicRules'))) {
1337:                 $elementId = $element->getId();
1338:                 $elementIds[] = $elementId;
1339:                 $logic[$elementId] = array(
1340:                     'action' => $element->config('logicAction'),
1341:                     'match' => $element->config('logicMatch'),
1342:                     'rules' => $element->config('logicRules')
1343:                 );
1344: 
1345:                 foreach ($element->config('logicRules') as $elementLogicRule) {
1346:                     if ( ! isset($dependents[$elementLogicRule['elementId']])) {
1347:                         $dependents[$elementLogicRule['elementId']] = array();
1348:                     }
1349: 
1350:                     $dependents[$elementLogicRule['elementId']][] = $elementId;
1351:                     $dependentElementIds[] = $elementLogicRule['elementId'];
1352:                 }
1353:             }
1354:         }
1355: 
1356:         return array(
1357:             'logic' => $logic,
1358:             'dependents' => $dependents,
1359:             'elementIds' => $elementIds,
1360:             'dependentElementIds' => array_values(array_unique($dependentElementIds)),
1361:             'animate' => $this->config('logicAnimation')
1362:         );
1363:     }
1364: 
1365:     /**
1366:      * Get the CSS for this form
1367:      *
1368:      * @return  string
1369:      */
1370:     public function getCss()
1371:     {
1372:         $css = '';
1373:         $styles = array();
1374: 
1375:         // Mapping of form style options to global styles
1376:         $map = array(
1377:             array('verticalElementSpacing', 'padding-bottom: %s;', 'elementSpacer'),
1378:             array('width', 'width: %s;', 'formOuter'),
1379:             array('labelTextColor', 'color: %s;', 'elementLabelText'),
1380:             array('requiredTextColor', 'color: %s;', 'elementRequiredText'),
1381:             array('fieldBackgroundColor', 'background-color: %s;', 'elementText', 'elementTextarea', 'elementSelect'),
1382:             array('fieldBackgroundColorHover', 'background-color: %s;', 'elementTextHover', 'elementTextareaHover', 'elementSelectHover'),
1383:             array('fieldBackgroundColorFocus', 'background-color: %s;', 'elementTextFocus', 'elementTextareaFocus', 'elementSelectFocus', 'timeDropdown', 'select2Drop', 'select2DropBorders'),
1384:             array('fieldBackgroundColorFocus', 'border-color: rgba(0,0,0,0.2);', 'select2DropBorders'),
1385:             array('fieldBorderColor', 'border-color: %s;', 'elementText', 'elementTextarea', 'elementSelect'),
1386:             array('fieldBorderColorHover', 'border-color: %s;', 'elementTextHover', 'elementTextareaHover', 'elementSelectHover'),
1387:             array('fieldBorderColorFocus', 'border-color: %s;', 'elementTextFocus', 'elementTextareaFocus', 'elementSelectFocus', 'timeDropdown', 'select2Drop'),
1388:             array('fieldTextColor', 'color: %s;', 'elementText', 'elementTextarea', 'elementSelect', 'elementIcon', 'select2DropText'),
1389:             array('fieldTextColorHover', 'color: %s;', 'elementTextHover', 'elementTextareaHover', 'elementSelectHover', 'elementIconHover'),
1390:             array('fieldTextColorFocus', 'color: %s;', 'elementTextFocus', 'elementTextareaFocus', 'elementSelectFocus', 'timeDropdown', 'select2Drop', 'timeDropdownText', 'select2DropTextFocus', 'select2DropBorders'),
1391:             array('buttonBackgroundColor', 'background-color: %s;', 'submitButton', 'backButton', 'nextButton', 'uploadButton'),
1392:             array('buttonBackgroundColorHover', 'background-color: %s;', 'submitButtonHover', 'backButtonHover', 'nextButtonHover', 'uploadButtonHover'),
1393:             array('buttonBackgroundColorActive', 'background-color: %s;', 'submitButtonActive', 'backButtonActive', 'nextButtonActive', 'uploadButtonActive'),
1394:             array('buttonBorderColor', 'border-color: %s;', 'submitButton', 'backButton', 'nextButton', 'uploadButton'),
1395:             array('buttonBorderColorHover', 'border-color: %s;', 'submitButtonHover', 'backButtonHover', 'nextButtonHover', 'uploadButtonHover'),
1396:             array('buttonBorderColorActive', 'border-color: %s;', 'submitButtonActive', 'backButtonActive', 'nextButtonActive', 'uploadButtonActive'),
1397:             array('buttonTextColor', 'color: %s;', 'submitButtonText', 'backButtonText', 'nextButtonText', 'uploadButtonText'),
1398:             array('buttonTextColorHover', 'color: %s;', 'submitButtonTextHover', 'backButtonTextHover', 'nextButtonTextHover', 'uploadButtonTextHover'),
1399:             array('buttonTextColorActive', 'color: %s;', 'submitButtonTextActive', 'backButtonTextActive', 'nextButtonTextActive', 'uploadButtonTextActive'),
1400:             array('buttonIconColor', 'color: %s;', 'submitButtonIcon', 'backButtonIcon', 'nextButtonIcon', 'uploadButtonIcon'),
1401:             array('buttonIconColorHover', 'color: %s;', 'submitButtonIconHover', 'backButtonIconHover', 'nextButtonIconHover', 'uploadButtonIconHover'),
1402:             array('buttonIconColorActive', 'color: %s;', 'submitButtonIconActive', 'backButtonIconActive', 'nextButtonIconActive', 'uploadButtonIconActive'),
1403:         );
1404: 
1405:         foreach ($map as $selectors) {
1406:             $value = $this->config(array_shift($selectors));
1407: 
1408:             if (Quform::isNonEmptyString($value)) {
1409:                 $rule = sprintf(array_shift($selectors), $value);
1410: 
1411:                 foreach ($selectors as $selector) {
1412:                     $styles[] = array('type' => trim($selector), 'css' => $rule);
1413:                 }
1414:             }
1415:         }
1416: 
1417:         $styles = array_merge($styles, $this->config('styles'));
1418: 
1419:         foreach ($styles as $style) {
1420:             $selector = $this->getCssSelector($style['type']);
1421: 
1422:             if ( ! empty($selector) && ! empty($style['css'])) {
1423:                 $css .= sprintf('%s { %s }', $selector, $style['css']);
1424:             }
1425:         }
1426: 
1427:         $theme = $this->config('theme');
1428:         if (Quform::isNonEmptyString($theme)) {
1429:             $css .= Quform_Themes::getPrimaryColorCustomCss($theme, $this->getId(), $this->config('themePrimaryColor'));
1430:             $css .= Quform_Themes::getSecondaryColorCustomCss($theme, $this->getId(), $this->config('themeSecondaryColor'));
1431:             $css .= Quform_Themes::getPrimaryForegroundColorCustomCss($theme, $this->getId(), $this->config('themePrimaryForegroundColor'));
1432:             $css .= Quform_Themes::getSecondaryForegroundColorCustomCss($theme, $this->getId(), $this->config('themeSecondaryForegroundColor'));
1433:         }
1434: 
1435:         if ($this->config('responsiveElements') == 'custom' && Quform::isNonEmptyString($this->config('responsiveElementsCustom'))) {
1436:             $css .= sprintf('@media (max-width: %s) {', Quform::addCssUnit($this->config('responsiveElementsCustom')));
1437:             $css .= sprintf('
1438:                 .quform-%1$d .quform-input,
1439:                 .quform-%1$d .quform-upload-dropzone {
1440:                     width: 100%% !important;
1441:                     min-width: 10px;
1442:                 }
1443:                 .quform-%1$d .quform-error > .quform-error-inner {
1444:                     float: none;
1445:                     display: block;
1446:                 }
1447:                 .quform-%1$d .quform-element-submit button {
1448:                     margin: 0;
1449:                     width: 100%%;
1450:                 }
1451:                 .quform-%1$d .quform-element-submit.quform-button-width-full > .quform-button-submit-default,
1452:                 .quform-%1$d .quform-element-submit.quform-button-width-full > .quform-button-back-default,
1453:                 .quform-%1$d .quform-element-submit.quform-button-width-full > .quform-button-next-default {
1454:                     width: 100%%;
1455:                     float: none;
1456:                 }
1457:                 .quform-%1$d .quform-button-next-default,
1458:                 .quform-%1$d .quform-button-back-default,
1459:                 .quform-%1$d .quform-button-submit-default {
1460:                     float: none;
1461:                     margin: 5px 0;
1462:                 }
1463:                 .quform-%1$d .quform-loading-position-left {
1464:                     padding-left: 0;
1465:                 }
1466:                 .quform-%1$d .quform-loading-position-right {
1467:                     padding-right: 0;
1468:                 }
1469:                 .quform-%1$d .quform-labels-left > .quform-spacer > .quform-label {
1470:                     float: none;
1471:                     width: auto;
1472:                 }
1473:                 .quform-%1$d .quform-labels-left.quform-element > .quform-spacer > .quform-inner {
1474:                     margin-left: 0 !important;
1475:                     padding-left: 0 !important;
1476:                     margin-right: 0 !important;
1477:                     padding-right: 0 !important;
1478:                 }
1479:                 .quform-%1$d .select2-container--quform .select2-selection--multiple .select2-selection__choice {
1480:                     display: block;
1481:                     float: none;
1482:                     width: auto;
1483:                     padding-top: 10px;
1484:                     padding-bottom: 10px;
1485:                     margin-right: 25px;
1486:                 }
1487:                 ', $this->getId());
1488:             $css .= '}';
1489:         }
1490: 
1491:         if ($this->config('responsiveColumns') == 'custom' && Quform::isNonEmptyString($this->config('responsiveColumnsCustom'))) {
1492:             $css .= sprintf('@media (max-width: %s) {', Quform::addCssUnit($this->config('responsiveColumnsCustom')));
1493:             $css .= sprintf('
1494:                 .quform-%1$d .quform-element-row > .quform-element-column,
1495:                 .quform-%1$d .quform-options-columns > .quform-option {
1496:                     float: none;
1497:                     width: 100%% !important;
1498:                 }
1499:                 ', $this->getId());
1500:             $css .= '}';
1501:         }
1502: 
1503:         if (Quform::isNonEmptyString($this->config('fieldPlaceholderStyles'))) {
1504:             // The selectors must be separate for this to work
1505:             $css .= sprintf(
1506:                 '.quform-%1$d ::-webkit-input-placeholder {
1507:                     %2$s
1508:                 }
1509:                 .quform-%1$d :-moz-placeholder {
1510:                     %2$s
1511:                 }
1512:                 .quform-%1$d ::-moz-placeholder {
1513:                     %2$s
1514:                 }
1515:                 .quform-%1$d :-ms-input-placeholder {
1516:                     %2$s
1517:                 }
1518:                 .quform-%1$d ::placeholder {
1519:                     %2$s
1520:                 }',
1521:                 $this->getId(),
1522:                 $this->config('fieldPlaceholderStyles')
1523:             );
1524:         }
1525: 
1526:         if (Quform::isNonEmptyString($this->config('loadingColor'))) {
1527:             if ($this->config('loadingType') == 'spinner-1') {
1528:                 $css .= sprintf(
1529:                     '.quform-%1$d .quform-loading-type-spinner-1 .quform-loading-spinner,
1530:                     .quform-%1$d .quform-loading-type-spinner-1 .quform-loading-spinner:after { border-top-color: %2$s; }',
1531:                     $this->getId(),
1532:                     $this->config('loadingColor')
1533:                 );
1534:             } else if ($this->config('loadingType') == 'spinner-2') {
1535:                 $css .= sprintf(
1536:                     '.quform-%1$d .quform-loading-type-spinner-2 .quform-loading-spinner { background-color: %2$s; }',
1537:                     $this->getId(),
1538:                     $this->config('loadingColor')
1539:                 );
1540:             } else if ($this->config('loadingType') == 'spinner-3') {
1541:                 $css .= sprintf(
1542:                     '.quform-%1$d .quform-loading-type-spinner-3 .quform-loading-spinner,
1543:                     .quform-%1$d .quform-loading-type-spinner-3 .quform-loading-spinner:after { color: %2$s; }',
1544:                     $this->getId(),
1545:                     $this->config('loadingColor')
1546:                 );
1547:             } else if ($this->config('loadingType') == 'spinner-4') {
1548:                 $css .= sprintf(
1549:                     '.quform-%1$d .quform-loading-type-spinner-4 .quform-loading-spinner:after { background-color: %2$s; }',
1550:                     $this->getId(),
1551:                     $this->config('loadingColor')
1552:                 );
1553:             } else if ($this->config('loadingType') == 'spinner-5') {
1554:                 $css .= sprintf(
1555:                     '.quform-%1$d .quform-loading-type-spinner-5 .quform-loading-spinner { border-left-color: %2$s; }',
1556:                     $this->getId(),
1557:                     $this->config('loadingColor')
1558:                 );
1559:             } else if ($this->config('loadingType') == 'spinner-6') {
1560:                 $css .= sprintf(
1561:                     '.quform-%1$d .quform-loading-type-spinner-6 .quform-loading-spinner-inner { color: %2$s; }',
1562:                     $this->getId(),
1563:                     $this->config('loadingColor')
1564:                 );
1565:             } else if ($this->config('loadingType') == 'spinner-7') {
1566:                 $css .= sprintf(
1567:                     '.quform-%1$d .quform-loading-type-spinner-7 .quform-loading-spinner-inner,
1568:                     .quform-%1$d .quform-loading-type-spinner-7 .quform-loading-spinner-inner:before,
1569:                     .quform-%1$d .quform-loading-type-spinner-7 .quform-loading-spinner-inner:after { background-color: %2$s; color: %2$s; }',
1570:                      $this->getId(),
1571:                     $this->config('loadingColor')
1572:                 );
1573:             } else if ($this->config('loadingType') == 'custom') {
1574:                 $css .= sprintf(
1575:                     '.quform-%1$d .quform-loading-type-custom .quform-loading-inner { color: %2$s; }',
1576:                     $this->getId(),
1577:                     $this->config('loadingColor')
1578:                 );
1579:             }
1580:         }
1581: 
1582:         if ($this->config('loadingOverlay') && Quform::isNonEmptyString($this->config('loadingOverlayColor'))) {
1583:             $css .= sprintf(
1584:                 '.quform-%1$d .quform-loading-overlay, .quform-%1$d .quform-loading.quform-loading-triggered.quform-loading-position-over-button { background-color: %2$s; }',
1585:                 $this->getId(),
1586:                 $this->config('loadingOverlayColor')
1587:             );
1588:         }
1589: 
1590:         foreach ($this->pages as $page) {
1591:             $css .= $page->getCss($this->getContext());
1592:         }
1593: 
1594:         $css .= apply_filters('quform_custom_css_' . $this->getId(), '', $this);
1595: 
1596:         return $css;
1597:     }
1598: 
1599:     /**
1600:      * Get the list of CSS selectors
1601:      *
1602:      * @return array
1603:      */
1604:     protected function getCssSelectors()
1605:     {
1606:         return array(
1607:             'formOuter' => '%s',
1608:             'formInner' => '%s .quform-form-inner',
1609:             'formSuccess' => '%s .quform-success-message',
1610:             'formSuccessIcon' => '%s .quform-success-message-icon',
1611:             'formSuccessContent' => '%s .quform-success-message-content',
1612:             'formTitle' => '%s .quform-form-title',
1613:             'formDescription' => '%s .quform-form-description',
1614:             'formElements' => '%s .quform-elements',
1615:             'formError' => '%s .quform-error-message',
1616:             'formErrorInner' => '%s .quform-error-message-inner',
1617:             'formErrorTitle' => '%s .quform-error-message-title',
1618:             'formErrorContent' => '%s .quform-error-message-content',
1619:             'element' => '%s .quform-element',
1620:             'elementLabel' => '%s .quform-label',
1621:             'elementLabelText' => '%s .quform-label > label',
1622:             'elementRequiredText' => '%s .quform-label > label > .quform-required',
1623:             'elementInner' => '%s .quform-inner',
1624:             'elementInput' => '%s .quform-input',
1625:             'elementText' => '
1626:                 %1$s .select2-container--quform .select2-selection,
1627:                 %1$s .quform-field-text,
1628:                 %1$s .quform-field-email,
1629:                 %1$s .quform-field-date,
1630:                 %1$s .quform-field-time,
1631:                 %1$s .quform-field-captcha,
1632:                 %1$s .quform-field-password',
1633:             'elementTextHover' => '
1634:                 %1$s .select2-container--quform .select2-selection:hover,
1635:                 %1$s .quform-field-text:hover,
1636:                 %1$s .quform-field-email:hover,
1637:                 %1$s .quform-field-date:hover,
1638:                 %1$s .quform-field-time:hover,
1639:                 %1$s .quform-field-captcha:hover,
1640:                 %1$s .quform-field-password:hover',
1641:             'elementTextFocus' => '
1642:                 %1$s .select2-container--quform.select2-container--open .select2-selection,
1643:                 %1$s .quform-field-text:focus,
1644:                 %1$s .quform-field-email:focus,
1645:                 %1$s .quform-field-date:focus,
1646:                 %1$s .quform-field-time:focus,
1647:                 %1$s .quform-field-captcha:focus,
1648:                 %1$s .quform-field-password:focus,
1649:                 %1$s .quform-field-text:active,
1650:                 %1$s .quform-field-email:active,
1651:                 %1$s .quform-field-date:active,
1652:                 %1$s .quform-field-time:active,
1653:                 %1$s .quform-field-captcha:active,
1654:                 %1$s .quform-field-password:active',
1655:             'elementTextarea' => '%s .quform-field-textarea',
1656:             'elementTextareaHover' => '%s .quform-field-textarea:hover',
1657:             'elementTextareaFocus' => '
1658:                 %1$s .quform-field-textarea:focus,
1659:                 %1$s .quform-field-textarea:active',
1660:             'elementSelect' => '
1661:                 %1$s .quform-field-select,
1662:                 %1$s .quform-field-multiselect',
1663:             'elementSelectHover' => '
1664:                 %1$s .quform-field-select:hover,
1665:                 %1$s .quform-field-multiselect:hover',
1666:             'elementSelectFocus' => '
1667:                 %1$s .quform-field-select:focus,
1668:                 %1$s .quform-field-select:active,
1669:                 %1$s .quform-field-multiselect:focus,
1670:                 %1$s .quform-field-multiselect:active',
1671:             'elementIcon' => '
1672:                 %1$s .select2-container--quform .select2-selection--multiple .select2-selection__rendered:before,
1673:                 %1$s .select2-container--quform .select2-selection__arrow b,
1674:                 %1$s-select2.select2-container--quform .select2-search--dropdown:before,
1675:                 %1$s .quform-field-icon',
1676:             'elementIconHover' => '
1677:                 %1$s .select2-container--quform .select2-selection--multiple .select2-selection__rendered:hover:before,
1678:                 %1$s .select2-container--quform .select2-selection__arrow b:hover,
1679:                 %1$s-select2.select2-container--quform .select2-search--dropdown:hover:before,
1680:                 %1$s .quform-field-icon:hover',
1681:             'timeDropdown' => '
1682:                 %s-timepicker.quform-timepicker.k-list-container.k-popup',
1683:             'timeDropdownText' => '
1684:                 %1$s-timepicker.quform-timepicker.k-popup ul.k-list li.k-item.k-state-selected,
1685:                 %1$s-timepicker.quform-timepicker.k-popup ul.k-list li.k-item,
1686:                 %1$s-timepicker.quform-timepicker.k-popup ul.k-list li.k-item.k-state-hover',
1687:             'select2Drop' => '
1688:                 %s-select2.select2-container--quform .select2-dropdown',
1689:             'select2DropBorders' => '
1690:                 %1$s-timepicker.quform-timepicker.k-popup ul.k-list li.k-item.k-state-hover,
1691:                 %1$s-select2.select2-container--quform .select2-dropdown--below .select2-results__options,
1692:                 %1$s-select2.select2-container--quform .select2-results__option--highlighted[aria-selected],
1693:                 %1$s-select2.select2-container--quform .select2-search--dropdown .select2-search__field',
1694:             'select2DropText' => '%s .select2-container--quform .select2-search--inline .select2-search__field',
1695:             'select2DropTextFocus' => '
1696:                 %1$s-select2.select2-container--quform .select2-results__options[aria-multiselectable="true"] .select2-results__option[aria-selected="true"],
1697:                 %1$s .select2-container--quform .select2-search--inline .select2-search__field:focus,
1698:                 %1$s-select2.select2-container--quform .select2-results__option,
1699:                 %1$s-select2.quform-timepicker.k-popup ul.k-list li.k-item,
1700:                 %1$s-select2.quform-timepicker.k-popup ul.k-list li.k-item.k-state-hover',
1701:             'elementDescription' => '%s .quform-description',
1702:             'elementSpacer' => '%1$s .quform-spacer,
1703: %1$s .quform-element-group.quform-group-style-bordered > .quform-spacer,
1704: %1$s .quform-group-style-bordered > .quform-child-elements',
1705:             'elementSubLabel' => '%s .quform-sub-label',
1706:             'options' => '%s .quform-options',
1707:             'option' => '%s .quform-option',
1708:             'optionRadioButton' => '%s .quform-option .quform-field-radio',
1709:             'optionCheckbox' => '%s .quform-option .quform-field-checkbox',
1710:             'optionLabel' => '%1$s .quform-options .quform-option .quform-option-label',
1711:             'optionLabelHover' => '%1$s .quform-options .quform-option .quform-option-label:hover',
1712:             'optionLabelSelected' => '%1$s .quform-options .quform-option .quform-field:checked + .quform-option-label',
1713:             'optionIcon' => '%1$s .quform-option .quform-option-icon',
1714:             'optionIconSelected' => '%1$s .quform-option .quform-option-icon-selected',
1715:             'optionText' => '%1$s .quform-option .quform-option-text',
1716:             'optionTextSelected' => '%1$s .quform-option .quform-field:checked + .quform-option-label .quform-option-text',
1717:             'elementError' => '%s .quform-error',
1718:             'elementErrorInner' => '%s .quform-error > .quform-error-inner',
1719:             'elementErrorText' => '%s .quform-error > .quform-error-inner > .quform-error-text',
1720:             'page' => '%s .quform-element-page',
1721:             'pageTitle' => '%s .quform-page-title',
1722:             'pageDescription' => '%s .quform-page-description',
1723:             'pageElements' => '%s .quform-element-page > .quform-child-elements',
1724:             'group' => '%s .quform-element-group',
1725:             'groupTitle' => '%s .quform-spacer > .quform-group-title-description quform-group-title',
1726:             'groupDescription' => '%s .quform-spacer > .quform-group-title-description p.quform-group-description',
1727:             'groupElements' => '%s .quform-element-group > .quform-spacer > .quform-child-elements',
1728:             'pageProgress' => '%s .quform-page-progress',
1729:             'pageProgressBar' => '%s .quform-page-progress-bar',
1730:             'pageProgressBarText' => '%s .quform-page-progress-text',
1731:             'pageProgressTabs' => '%s .quform-page-progress-tabs',
1732:             'pageProgressTab' => '%s .quform-page-progress-tab',
1733:             'pageProgressTabActive' => '%s .quform-page-progress-tab.quform-current-tab',
1734:             'submit' => '%s .quform-element-submit',
1735:             'submitInner' => '%s .quform-button-submit',
1736:             'submitButton' => '%1$s .quform-button-submit button, %1$s .quform-element-submit.quform-button-style-theme .quform-button-submit button',
1737:             'submitButtonHover' => '%1$s .quform-button-submit button:hover, %1$s .quform-element-submit.quform-button-style-theme .quform-button-submit button:hover',
1738:             'submitButtonActive' => '%1$s .quform-button-submit button:active, %1$s .quform-element-submit.quform-button-style-theme .quform-button-submit button:active',
1739:             'submitButtonText' => '%1$s .quform-button-submit button .quform-button-text, %1$s .quform-element-submit.quform-button-style-theme .quform-button-submit button .quform-button-text',
1740:             'submitButtonTextHover' => '%1$s .quform-button-submit button:hover .quform-button-text, %1$s .quform-element-submit.quform-button-style-theme .quform-button-submit button:hover .quform-button-text',
1741:             'submitButtonTextActive' => '%1$s .quform-button-submit button:active .quform-button-text, %1$s .quform-element-submit.quform-button-style-theme .quform-button-submit button:active .quform-button-text',
1742:             'submitButtonIcon' => '%1$s .quform-button-submit button .quform-button-icon, %1$s .quform-element-submit.quform-button-style-theme .quform-button-submit button .quform-button-icon',
1743:             'submitButtonIconHover' => '%1$s .quform-button-submit button:hover .quform-button-icon, %1$s .quform-element-submit.quform-button-style-theme .quform-button-submit button:hover .quform-button-icon',
1744:             'submitButtonIconActive' => '%1$s .quform-button-submit button:active .quform-button-icon, %1$s .quform-element-submit.quform-button-style-theme .quform-button-submit button:active .quform-button-icon',
1745:             'backInner' => '%s .quform-button-back',
1746:             'backButton' => '%1$s .quform-button-back button, %1$s .quform-element-submit.quform-button-style-theme .quform-button-back button',
1747:             'backButtonHover' => '%1$s .quform-button-back button:hover, %1$s .quform-element-submit.quform-button-style-theme .quform-button-back button:hover',
1748:             'backButtonActive' => '%1$s .quform-button-back button:active, %1$s .quform-element-submit.quform-button-style-theme .quform-button-back button:active',
1749:             'backButtonText' => '%1$s .quform-button-back button .quform-button-text, %1$s .quform-element-submit.quform-button-style-theme .quform-button-back button .quform-button-text',
1750:             'backButtonTextHover' => '%1$s .quform-button-back button:hover .quform-button-text, %1$s .quform-element-submit.quform-button-style-theme .quform-button-back button:hover .quform-button-text',
1751:             'backButtonTextActive' => '%1$s .quform-button-back button:active .quform-button-text, %1$s .quform-element-submit.quform-button-style-theme .quform-button-back button:active .quform-button-text',
1752:             'backButtonIcon' => '%1$s .quform-button-back button .quform-button-icon, %1$s .quform-element-submit.quform-button-style-theme .quform-button-back button .quform-button-icon',
1753:             'backButtonIconHover' => '%1$s .quform-button-back button:hover .quform-button-icon, %1$s .quform-element-submit.quform-button-style-theme .quform-button-back button:hover .quform-button-icon',
1754:             'backButtonIconActive' => '%1$s .quform-button-back button:active .quform-button-icon, %1$s .quform-element-submit.quform-button-style-theme .quform-button-back button:active .quform-button-icon',
1755:             'nextInner' => '%s .quform-button-next',
1756:             'nextButton' => '%1$s .quform-button-next button, %1$s .quform-element-submit.quform-button-style-theme .quform-button-next button',
1757:             'nextButtonHover' => '%1$s .quform-button-next button:hover, %1$s .quform-element-submit.quform-button-style-theme .quform-button-next button:hover',
1758:             'nextButtonActive' => '%1$s .quform-button-next button:active, %1$s .quform-element-submit.quform-button-style-theme .quform-button-next button:active',
1759:             'nextButtonText' => '%1$s .quform-button-next button .quform-button-text, %1$s .quform-element-submit.quform-button-style-theme .quform-button-next button .quform-button-text',
1760:             'nextButtonTextHover' => '%1$s .quform-button-next button:hover .quform-button-text, %1$s .quform-element-submit.quform-button-style-theme .quform-button-next button:hover .quform-button-text',
1761:             'nextButtonTextActive' => '%1$s .quform-button-next button:active .quform-button-text, %1$s .quform-element-submit.quform-button-style-theme .quform-button-next button:active .quform-button-text',
1762:             'nextButtonIcon' => '%1$s .quform-button-next button .quform-button-icon, %1$s .quform-element-submit.quform-button-style-theme .quform-button-next button .quform-button-icon',
1763:             'nextButtonIconHover' => '%1$s .quform-button-next button:hover .quform-button-icon, %1$s .quform-element-submit.quform-button-style-theme .quform-button-next button:hover .quform-button-icon',
1764:             'nextButtonIconActive' => '%1$s .quform-button-next button:active .quform-button-icon, %1$s .quform-element-submit.quform-button-style-theme .quform-button-next button:active .quform-button-icon',
1765:             'uploadButton' => '%1$s .quform-upload-button, %1$s .quform-button-style-theme .quform-upload-button',
1766:             'uploadButtonHover' => '%1$s .quform-upload-button:hover, %1$s .quform-button-style-theme .quform-upload-button:hover',
1767:             'uploadButtonActive' => '%1$s .quform-upload-button:active, %1$s .quform-button-style-theme .quform-upload-button:active',
1768:             'uploadButtonText' => '%1$s .quform-upload-button .quform-upload-button-text, %1$s .quform-button-style-theme .quform-upload-button .quform-upload-button-text',
1769:             'uploadButtonTextHover' => '%1$s .quform-upload-button:hover .quform-upload-button-text, %1$s .quform-button-style-theme .quform-upload-button:hover .quform-upload-button-text',
1770:             'uploadButtonTextActive' => '%1$s .quform-upload-button:active .quform-upload-button-text, %1$s .quform-button-style-theme .quform-upload-button:active .quform-upload-button-text',
1771:             'uploadButtonIcon' => '%1$s .quform-upload-button .quform-upload-button-icon, %1$s .quform-button-style-theme .quform-upload-button .quform-upload-button-icon',
1772:             'uploadButtonIconHover' => '%1$s .quform-upload-button:hover .quform-upload-button-icon, %1$s .quform-button-style-theme .quform-upload-button:hover .quform-upload-button-icon',
1773:             'uploadButtonIconActive' => '%1$s .quform-upload-button:active .quform-upload-button-icon, %1$s .quform-button-style-theme .quform-upload-button:active .quform-upload-button-icon',
1774:             'uploadDropzone' => '%1$s .quform-upload-dropzone',
1775:             'uploadDropzoneHover' => '%1$s .quform-upload-dropzone:hover',
1776:             'uploadDropzoneActive' => '%1$s .quform-upload-dropzone:active',
1777:             'uploadDropzoneText' => '%1$s .quform-upload-dropzone .quform-upload-dropzone-text',
1778:             'uploadDropzoneTextHover' => '%1$s .quform-upload-dropzone:hover .quform-upload-dropzone-text',
1779:             'uploadDropzoneTextActive' => '%1$s .quform-upload-dropzone:active .quform-upload-dropzone-text',
1780:             'uploadDropzoneIcon' => '%1$s .quform-upload-dropzone .quform-upload-dropzone-icon',
1781:             'uploadDropzoneIconHover' => '%1$s .quform-upload-dropzone:hover .quform-upload-dropzone-icon',
1782:             'uploadDropzoneIconActive' => '%1$s .quform-upload-dropzone:active .quform-upload-dropzone-icon',
1783:             'datepickerHeader' => '%1$s-datepicker.quform-datepicker .k-calendar .k-header, %1$s-datepicker.quform-datepicker .k-calendar .k-header .k-state-hover',
1784:             'datepickerHeaderText' => '%s-datepicker.quform-datepicker .k-calendar .k-header .k-link',
1785:             'datepickerHeaderTextHover' => '%s-datepicker.quform-datepicker .k-calendar .k-header .k-link:hover',
1786:             'datepickerFooter' => '%s-datepicker.quform-datepicker .k-calendar .k-footer',
1787:             'datepickerFooterText' => '%s-datepicker.quform-datepicker .k-calendar .k-footer .k-link',
1788:             'datepickerFooterTextHover' => '%s-datepicker.quform-datepicker .k-calendar .k-footer .k-link:hover',
1789:             'datepickerSelectionText' => '%s-datepicker.quform-datepicker .k-calendar td.k-state-focused .k-link',
1790:             'datepickerSelectionTextHover' => '%s-datepicker.quform-datepicker .k-calendar td.k-state-focused .k-link:hover',
1791:             'datepickerSelectionActiveText' => '%s-datepicker.quform-datepicker .k-calendar td.k-state-selected.k-state-focused .k-link',
1792:             'datepickerSelectionActiveTextHover' => '%s-datepicker.quform-datepicker .k-calendar td.k-state-selected.k-state-focused .k-link:hover',
1793:             'datepickerSelection' => '%s-datepicker.quform-datepicker .k-calendar td.k-state-focused',
1794:             'datepickerSelectionActive' => '%s-datepicker.quform-datepicker .k-calendar td.k-state-selected.k-state-focused',
1795:         );
1796:     }
1797: 
1798:     /**
1799:      * Get the CSS selector for the given style type
1800:      *
1801:      * @param   string  $type
1802:      * @return  string
1803:      */
1804:     protected function getCssSelector($type)
1805:     {
1806:         $selector = '';
1807:         $selectors = $this->getCssSelectors();
1808: 
1809:         if (array_key_exists($type, $selectors)) {
1810:             $prefix = sprintf('.quform-%d', $this->getId());
1811:             $selector = sprintf($selectors[$type], $prefix);
1812:         }
1813: 
1814:         return $selector;
1815:     }
1816: 
1817:     /**
1818:      * Does the form have at least one File Upload element with enhanced upload enabled?
1819:      *
1820:      * @return boolean
1821:      */
1822:     public function hasEnhancedFileUploadElement()
1823:     {
1824:         foreach ($this->getRecursiveIterator() as $element) {
1825:             if ($element instanceof Quform_Element_File && $element->config('enhancedUploadEnabled')) {
1826:                 return true;
1827:             }
1828:         }
1829: 
1830:         return false;
1831:     }
1832: 
1833:     /**
1834:      * Sets whether the form been successfully submitted
1835:      *
1836:      * @param boolean $flag
1837:      */
1838:     public function setSubmitted($flag)
1839:     {
1840:         $this->submitted = (bool) $flag;
1841:     }
1842: 
1843:     /**
1844:      * Has the form been successfully submitted?
1845:      *
1846:      * @return boolean
1847:      */
1848:     public function isSubmitted()
1849:     {
1850:         return $this->submitted;
1851:     }
1852: 
1853:     /**
1854:      * Reset all form values to their default
1855:      */
1856:     public function reset()
1857:     {
1858:         foreach ($this->getRecursiveIterator() as $element) {
1859:             if ( ! $element instanceof Quform_Element_Field) {
1860:                 continue;
1861:             }
1862: 
1863:             switch ($this->getConfirmation()->config('resetForm')) {
1864:                 default:
1865:                 case '':
1866:                     $element->reset();
1867:                     break;
1868:                 case 'clear':
1869:                     $element->setValue($element->getEmptyValue());
1870:                     break;
1871:                 case 'keep':
1872:                     /* Do nothing */
1873:                     break;
1874:             }
1875:         }
1876: 
1877:         $this->setCurrentPageById($this->getFirstPage()->getId());
1878:     }
1879: 
1880:     /**
1881:      * Sets the dynamic values
1882:      *
1883:      * @param string|array $dynamicValues
1884:      */
1885:     public function setDynamicValues($dynamicValues)
1886:     {
1887:         if (is_string($dynamicValues)) {
1888:             parse_str($dynamicValues, $dynamicValues);
1889:         }
1890: 
1891:         $this->dynamicValues = $dynamicValues;
1892:     }
1893: 
1894:     /**
1895:      * Get the dynamic values
1896:      *
1897:      * @return array
1898:      */
1899:     public function getDynamicValues()
1900:     {
1901:         return $this->dynamicValues;
1902:     }
1903: 
1904:     /**
1905:      * Server-side conditional logic processing, determines which form elements are hidden by conditional logic
1906:      */
1907:     public function calculateElementVisibility()
1908:     {
1909:         $ancestors = array();
1910:         $currentPage = null;
1911:         $this->calculateElementVisibilityHelper($this->pages, $ancestors, $currentPage);
1912:     }
1913: 
1914:     /**
1915:      * Recursive helper function for calculateElementVisibility
1916:      *
1917:      * @param  array                     $elements
1918:      * @param  array                     $ancestors
1919:      * @param  Quform_Element_Page|null  $currentPage
1920:      */
1921:     protected function calculateElementVisibilityHelper($elements, &$ancestors, &$currentPage)
1922:     {
1923:         foreach ($elements as $element) {
1924:             if ( ! $element instanceof Quform_Element_Field && ! $element instanceof Quform_Element_Container && ! $element instanceof Quform_Element_Html) {
1925:                 // Skip non-fields and containers
1926:                 continue;
1927:             }
1928: 
1929:             $isConditionallyHidden = false;
1930:             $hasNonVisibleAncestor = false;
1931:             $elementIsEmpty = $element->isEmpty();
1932: 
1933:             if ($elementIsEmpty && $element instanceof Quform_Element_File) {
1934:                 // Check for uploaded files pending processing
1935:                 $elementName = $element->getName();
1936: 
1937:                 if (
1938:                     array_key_exists($elementName, $_FILES) &&
1939:                     is_array($_FILES[$elementName]) &&
1940:                     array_key_exists('error', $_FILES[$elementName]) &&
1941:                     is_array($_FILES[$elementName]['error'])
1942:                 ) {
1943:                     foreach ($_FILES[$elementName]['error'] as $error) {
1944:                         if ($error == UPLOAD_ERR_OK) {
1945:                             $elementIsEmpty = false;
1946:                             break;
1947:                         }
1948:                     }
1949:                 }
1950:             }
1951: 
1952:             // Check if this element is hidden by its ancestor's conditional logic rules
1953:             foreach ($ancestors as $ancestor) {
1954:                 if ($ancestor->isConditionallyHidden()) {
1955:                     $isConditionallyHidden = true;
1956:                 }
1957: 
1958:                 if ( ! $ancestor->isVisible()) {
1959:                     $hasNonVisibleAncestor = true;
1960:                 }
1961: 
1962:                 if ( ! $elementIsEmpty) {
1963:                     $ancestor->setHasNonEmptyChild(true);
1964:                 }
1965:             }
1966: 
1967:             // If this page is hidden, so are all elements inside it
1968:             if ( ! $element instanceof Quform_Element_Page && $currentPage instanceof Quform_Element_Page && $currentPage->isConditionallyHidden()) {
1969:                 $isConditionallyHidden = true;
1970:             }
1971: 
1972:             // Calculate the visibility based on the logic rules
1973:             if ( ! $isConditionallyHidden && $element->config('logicEnabled') && count($element->config('logicRules'))) {
1974:                 if ( ! $this->checkLogicAction($element->config('logicAction'), $element->config('logicMatch'), $element->config('logicRules'))) {
1975:                     $isConditionallyHidden = true;
1976:                 }
1977:             }
1978: 
1979:             // Set the flags on the parent groups if we have a visible or non-empty element
1980:             foreach ($ancestors as $ancestor) {
1981:                 if ( ! $isConditionallyHidden) {
1982:                     $ancestor->setHasVisibleChild(true);
1983:                 }
1984:             }
1985: 
1986:             // Set the flag that this element is conditionally hidden, either by its own rules or by parent group rules
1987:             $element->setConditionallyHidden($isConditionallyHidden);
1988:             $element->setHasNonVisibleAncestor($hasNonVisibleAncestor);
1989: 
1990:             if ($element instanceof Quform_Element_Page) {
1991:                 $currentPage = $element;
1992:             }
1993: 
1994:             if ($element instanceof Quform_Element_Group || $element instanceof Quform_Element_Row || $element instanceof Quform_Element_Column) {
1995:                 array_push($ancestors, $element);
1996:                 $this->calculateElementVisibilityHelper($element->getElements(), $ancestors, $currentPage);
1997:                 array_pop($ancestors);
1998:             }
1999:         }
2000:     }
2001: 
2002:     /**
2003:      * Set the current page to the one with the given ID
2004:      *
2005:      * @param int $pageId
2006:      */
2007:     public function setCurrentPageById($pageId)
2008:     {
2009:         foreach ($this->pages as $pages) {
2010:             if ($pages->getId() == $pageId) {
2011:                 $this->currentPage = $pages;
2012:             }
2013:         }
2014:     }
2015: 
2016:     /**
2017:      * Get the current page being viewed/processed
2018:      *
2019:      * If no page is found it's set to the first page
2020:      *
2021:      * @return Quform_Element_Page
2022:      */
2023:     public function getCurrentPage()
2024:     {
2025:         if ( ! $this->currentPage) {
2026:             $this->currentPage = $this->getFirstPage();
2027:         }
2028: 
2029:         return $this->currentPage;
2030:     }
2031: 
2032:     /**
2033:      * Get the ID of the next page that isn't conditionally hidden
2034:      *
2035:      * @param   bool      $reverse  If true it will search in reverse and get the previous page
2036:      * @return  int|null            The ID of the next page or null if none found
2037:      */
2038:     public function getNextPageId($reverse = false)
2039:     {
2040:         $pages = $reverse ? array_reverse($this->pages, true) : $this->pages;
2041:         $currentPage = $this->getCurrentPage();
2042:         $foundCurrentPage = false;
2043: 
2044:         foreach ($pages as $page) {
2045:             if ($foundCurrentPage && ! $page->isConditionallyHidden()) {
2046:                 return $page->getId();
2047:             }
2048: 
2049:             if ($page == $currentPage) {
2050:                 $foundCurrentPage = true;
2051:             }
2052:         }
2053: 
2054:         return null;
2055:     }
2056: 
2057:     /**
2058:      * Get the total number of pages
2059:      *
2060:      * @return integer
2061:      */
2062:     public function getPageCount()
2063:     {
2064:         return count($this->pages);
2065:     }
2066: 
2067:     /**
2068:      * Does the form have more than one page?
2069:      *
2070:      * @return boolean
2071:      */
2072:     public function hasPages()
2073:     {
2074:         return $this->getPageCount() > 1;
2075:     }
2076: 
2077:     /**
2078:      * Get the array of page IDs
2079:      *
2080:      * Send to the JavaScript to determine progress percentage
2081:      *
2082:      * @return array
2083:      */
2084:     protected function getPageIds()
2085:     {
2086:         $pageIds = array();
2087: 
2088:         foreach ($this->pages as $page) {
2089:             $pageIds[] = $page->getId();
2090:         }
2091: 
2092:         return $pageIds;
2093:     }
2094: 
2095:     /**
2096:      * Set the current submitted entry ID
2097:      *
2098:      * @param   int|null     $entryId
2099:      * @return  Quform_Form
2100:      */
2101:     public function setEntryId($entryId)
2102:     {
2103:         $this->entryId = $entryId;
2104: 
2105:         return $this;
2106:     }
2107: 
2108:     /**
2109:      * Get the current submitted entry ID
2110:      *
2111:      * @return int|null
2112:      */
2113:     public function getEntryId()
2114:     {
2115:         return $this->entryId;
2116:     }
2117: 
2118:     /**
2119:      * Check the given logic data against the form data and return the action
2120:      *
2121:      * @param   string  $action
2122:      * @param   string  $match
2123:      * @param   array   $rules
2124:      * @return  bool
2125:      */
2126:     public function checkLogicAction($action, $match, array $rules)
2127:     {
2128:         $matches = 0;
2129:         $ruleCount = count($rules);
2130: 
2131:         for ($i = 0; $i < $ruleCount; $i++) {
2132:             if ($this->isLogicRuleMatch($rules[$i])) {
2133:                 $matches++;
2134:             }
2135:         }
2136: 
2137:         if ( ! (($match == 'any' && $matches > 0) || ($match == 'all' && $matches == $ruleCount))) {
2138:             // Invert the action, the rules don't match
2139:             $action = ! $action;
2140:         }
2141: 
2142:         return $action;
2143:     }
2144: 
2145:     /**
2146:      * Does the given logic rule pass with the current form data?
2147:      *
2148:      * @param   array  $rule
2149:      * @return  bool
2150:      */
2151:     protected function isLogicRuleMatch(array $rule)
2152:     {
2153:         $element = $this->getElementById($rule['elementId']);
2154: 
2155:         if ( ! $element instanceof Quform_Element_Field) {
2156:             return false;
2157:         }
2158: 
2159:         return $element->isLogicRuleMatch($rule);
2160:     }
2161: 
2162:     /**
2163:      * Get the first page of the form
2164:      *
2165:      * @return Quform_Element_Page|null
2166:      */
2167:     public function getFirstPage()
2168:     {
2169:         return reset($this->pages);
2170:     }
2171: 
2172:     /**
2173:      * Get the last page of the form
2174:      *
2175:      * @return Quform_Element_Page|null
2176:      */
2177:     public function getLastPage()
2178:     {
2179:         return end($this->pages);
2180:     }
2181: 
2182:     /**
2183:      * Get the session storage key for this form
2184:      *
2185:      * @return string
2186:      */
2187:     public function getSessionKey()
2188:     {
2189:         return 'quform-' . $this->getUniqueId();
2190:     }
2191: 
2192:     /**
2193:      * Get the CSRF protection token
2194:      *
2195:      * @return string
2196:      */
2197:     public function getCsrfToken()
2198:     {
2199:         return $this->session->getToken();
2200:     }
2201: 
2202:     /**
2203:      * Get the recursive iterator to iterate over the form elements
2204:      *
2205:      * Modes:
2206:      * RecursiveIteratorIterator::LEAVES_ONLY
2207:      * RecursiveIteratorIterator::SELF_FIRST
2208:      * RecursiveIteratorIterator::CHILD_FIRST
2209:      * RecursiveIteratorIterator::CATCH_GET_CHILD
2210:      *
2211:      * @param  int $mode
2212:      * @return RecursiveIteratorIterator
2213:      */
2214:     public function getRecursiveIterator($mode = RecursiveIteratorIterator::LEAVES_ONLY)
2215:     {
2216:         return new RecursiveIteratorIterator(
2217:             new Quform_Form_Iterator($this),
2218:             $mode
2219:         );
2220:     }
2221: 
2222:     /**
2223:      * Is the given unique ID valid?
2224:      *
2225:      * @param   string  $id
2226:      * @return  bool
2227:      */
2228:     public static function isValidUniqueId($id)
2229:     {
2230:         return is_string($id) && preg_match('/^[a-f0-9]{6}$/', $id);
2231:     }
2232: 
2233:     /**
2234:      * Generate a unique ID (6 digit hex)
2235:      *
2236:      * @return string
2237:      */
2238:     public static function generateUniqueId()
2239:     {
2240:         return sprintf('%06x', mt_rand(0, 0xffffff));
2241:     }
2242: 
2243:     /**
2244:      * @param   string  $key
2245:      * @param   string  $default
2246:      * @return  string
2247:      */
2248:     public function getTranslation($key, $default = '')
2249:     {
2250:         $string = $this->config($key);
2251: 
2252:         if (Quform::isNonEmptyString($string)) {
2253:             return $string;
2254:         }
2255: 
2256:         return $default;
2257:     }
2258: 
2259:     /**
2260:      * Get the default form configuration
2261:      *
2262:      * @param   string|null  $key  Get the config by key, if omitted the full config is returned
2263:      * @return  array
2264:      */
2265:     public static function getDefaultConfig($key = null)
2266:     {
2267:         $config = apply_filters('quform_default_config_form', array(
2268:             // General - Form
2269:             'name' => '',
2270:             'title' => '',
2271:             'titleTag' => 'h2',
2272:             'description' => '',
2273:             'active' => true,
2274:             'inactiveMessage' => '',
2275:             'trashed' => false,
2276:             'ajax' => true,
2277:             'saveEntry' => true,
2278:             'honeypot' => true,
2279:             'logicAnimation' => true,
2280: 
2281:             // General - Limits
2282:             'oneEntryPerUser' => false,
2283:             'oneEntryPer' => 'logged-in-user',
2284:             'limitEntries' => false,
2285:             'entryLimit' => '',
2286:             'entryLimitReachedMessage' => sprintf('<p>%s</p>', esc_html__('This form is currently closed for submissions.', 'quform')),
2287: 
2288:             // General - Scheduling
2289:             'enableSchedule' => false,
2290:             'scheduleStart' => '',
2291:             'scheduleStartMessage' => sprintf('<p>%s</p>', esc_html__('This form is not yet open for submissions.', 'quform')),
2292:             'scheduleEnd' => '',
2293:             'scheduleEndMessage' => sprintf('<p>%s</p>', esc_html__('This form is currently closed for submissions.', 'quform')),
2294: 
2295:             // Style - Global
2296:             'theme' => '',
2297:             'themePrimaryColor' => '',
2298:             'themeSecondaryColor' => '',
2299:             'themePrimaryForegroundColor' => '',
2300:             'themeSecondaryForegroundColor' => '',
2301:             'responsiveElements' => 'phone-landscape',
2302:             'responsiveElementsCustom' => '',
2303:             'responsiveColumns' => 'phone-landscape',
2304:             'responsiveColumnsCustom' => '',
2305:             'verticalElementSpacing' => '',
2306:             'width' => '',
2307:             'position' => '',
2308:             'previewColor' => '',
2309:             'styles' => array(),
2310: 
2311:             // Style - Labels
2312:             'labelTextColor' => '',
2313:             'labelPosition' => '',
2314:             'labelWidth' => '150px',
2315:             'requiredText' => '*',
2316:             'requiredTextColor' => '',
2317: 
2318:             // Style - Fields
2319:             'fieldSize' => '',
2320:             'fieldWidth' => '',
2321:             'fieldWidthCustom' => '',
2322:             'fieldBackgroundColor' => '',
2323:             'fieldBackgroundColorHover' => '',
2324:             'fieldBackgroundColorFocus' => '',
2325:             'fieldBorderColor' => '',
2326:             'fieldBorderColorHover' => '',
2327:             'fieldBorderColorFocus' => '',
2328:             'fieldTextColor' => '',
2329:             'fieldTextColorHover' => '',
2330:             'fieldTextColorFocus' => '',
2331:             'fieldPlaceholderStyles' => '',
2332: 
2333:             // Style - Buttons
2334:             'buttonStyle' => 'theme',
2335:             'buttonSize' => '',
2336:             'buttonWidth' => '',
2337:             'buttonWidthCustom' => '',
2338:             'buttonAnimation' => '',
2339:             'buttonBackgroundColor' => '',
2340:             'buttonBackgroundColorHover' => '',
2341:             'buttonBackgroundColorActive' => '',
2342:             'buttonBorderColor' => '',
2343:             'buttonBorderColorHover' => '',
2344:             'buttonBorderColorActive' => '',
2345:             'buttonTextColor' => '',
2346:             'buttonTextColorHover' => '',
2347:             'buttonTextColorActive' => '',
2348:             'buttonIconColor' => '',
2349:             'buttonIconColorHover' => '',
2350:             'buttonIconColorActive' => '',
2351:             'submitType' => 'default',
2352:             'submitText' => '',
2353:             'submitIcon' => '',
2354:             'submitIconPosition' => 'right',
2355:             'submitImage' => '',
2356:             'submitHtml' => '',
2357:             'nextType' => 'default',
2358:             'nextText' => '',
2359:             'nextIcon' => '',
2360:             'nextIconPosition' => 'right',
2361:             'nextImage' => '',
2362:             'nextHtml' => '',
2363:             'backType' => 'default',
2364:             'backText' => '',
2365:             'backIcon' => '',
2366:             'backIconPosition' => 'left',
2367:             'backImage' => '',
2368:             'backHtml' => '',
2369:             'backLocation' => '',
2370:             'optionsStyle' => '',
2371:             'optionsButtonStyle' => '',
2372:             'optionsButtonSize' => '',
2373:             'optionsButtonWidth' => '',
2374:             'optionsButtonWidthCustom' => '',
2375:             'optionsButtonIconPosition' => '',
2376: 
2377:             // Style - Pages
2378:             'pageProgressType' => 'numbers',
2379: 
2380:             // Style - Loading
2381:             'loadingType' => 'spinner-1',
2382:             'loadingCustom' => '',
2383:             'loadingPosition' => 'left',
2384:             'loadingColor' => '',
2385:             'loadingOverlay' => false,
2386:             'loadingOverlayColor' => '',
2387: 
2388:             // Style - Tooltips
2389:             'tooltipsEnabled' => true,
2390:             'tooltipType' => 'icon',
2391:             'tooltipEvent' => 'hover',
2392:             'tooltipIcon' => 'qicon-question-circle',
2393:             'tooltipStyle' => 'qtip-quform-dark',
2394:             'tooltipCustom' => '',
2395:             'tooltipMy' => 'left center',
2396:             'tooltipAt' => 'right center',
2397:             'tooltipShadow' => true,
2398:             'tooltipRounded' => false,
2399:             'tooltipClasses' => 'qtip-quform-dark qtip-shadow',
2400: 
2401:             // Notifications
2402:             'notifications' => array(),
2403:             'nextNotificationId' => 1,
2404: 
2405:             // Confirmations
2406:             'confirmations' => array(),
2407:             'nextConfirmationId' => 1,
2408: 
2409:             // Errors
2410:             'errorsPosition' => '',
2411:             'errorsIcon' => '',
2412:             'errorEnabled' => false,
2413:             'errorTitle' => '',
2414:             'errorContent' => '',
2415: 
2416:             // Language
2417:             'locale' => '',
2418:             'rtl' => 'global',
2419:             'dateFormatJs' => '',
2420:             'timeFormatJs' => '',
2421:             'dateTimeFormatJs' => '',
2422:             'dateFormat' => '',
2423:             'timeFormat' => '',
2424:             'dateTimeFormat' => '',
2425:             'messageRequired' => '',
2426:             'pageProgressNumbersText' => '',
2427:             'onlyOneSubmissionAllowed' => '',
2428:             'thisFormIsCurrentlyClosed' => '',
2429:             'formIsNotYetOpenForSubmissions' => '',
2430:             'formIsNoLongerOpenForSubmissions' => '',
2431: 
2432:             // Database
2433:             'databaseEnabled' => false,
2434:             'databaseWordpress' => true,
2435:             'databaseHost' => 'localhost',
2436:             'databaseUsername' => '',
2437:             'databasePassword' => '',
2438:             'databaseDatabase' => '',
2439:             'databaseTable' => '',
2440:             'databaseColumns' => array(),
2441: 
2442:             // Feature cache & locales
2443:             'hasDatepicker' => false,
2444:             'hasTimepicker' => false,
2445:             'hasEnhancedUploader' => false,
2446:             'hasEnhancedSelect' => false,
2447:             'locales' => array(),
2448: 
2449:             // Elements
2450:             'elements' => array(),
2451:             'nextElementId' => 1,
2452: 
2453:             // Misc
2454:             'entriesTableColumns' => array(),
2455:             'environment' => 'frontend'
2456:         ));
2457: 
2458:         if (Quform::isNonEmptyString($key)) {
2459:             return Quform::get($config, $key);
2460:         }
2461: 
2462:         return $config;
2463:     }
2464: }
2465: 
API documentation generated by ApiGen