public function updateDynamicListCMSFields($fields)
 {
     // Make sure the draft records are being looked at.
     $stage = Versioned::current_stage();
     Versioned::reading_stage('Stage');
     $used = EditableFormField::get()->filter(array('ClassName:PartialMatch' => 'DynamicList'));
     // Determine whether this dynamic list is being used anywhere.
     $found = array();
     foreach ($used as $field) {
         // This information is stored using a serialised list, therefore we need to iterate through.
         if ($field->getSetting('ListTitle') === $this->owner->Title) {
             // Make sure there are no duplicates recorded.
             if (!isset($found[$field->ParentID]) && ($form = UserDefinedForm::get()->byID($field->ParentID))) {
                 $found[$field->ParentID] = "<a href='{$form->CMSEditLink()}'>{$form->Title}</a>";
             }
         }
     }
     // Display whether there were any dynamic lists found on user defined forms.
     if (count($found)) {
         $fields->removeByName('UsedOnHeader');
         $fields->addFieldToTab('Root.Main', HeaderField::create('UsedOnHeader', 'Used On', 5));
     }
     $display = count($found) ? implode('<br>', $found) : 'This dynamic list is <strong>not</strong> used.';
     $fields->removeByName('UsedOn');
     $fields->addFieldToTab('Root.Main', LiteralField::create('UsedOn', '<div>' . $display . '</div>'));
     Versioned::reading_stage($stage);
 }
 public function php($data)
 {
     if (!parent::php($data)) {
         return false;
     }
     // Skip unsaved records
     if (empty($data['ID']) || !is_numeric($data['ID'])) {
         return true;
     }
     $fields = EditableFormField::get()->filter('ParentID', $data['ID'])->sort('"Sort" ASC');
     // Current nesting
     $stack = array();
     $conditionalStep = false;
     // Is the current step conditional?
     foreach ($fields as $field) {
         if ($field instanceof EditableFormStep) {
             // Page at top level, or after another page is ok
             if (empty($stack) || count($stack) === 1 && $stack[0] instanceof EditableFormStep) {
                 $stack = array($field);
                 $conditionalStep = $field->DisplayRules()->count() > 0;
                 continue;
             }
             $this->validationError('FormFields', _t("UserFormValidator.UNEXPECTED_BREAK", "Unexpected page break '{name}' inside nested field '{group}'", array('name' => $field->CMSTitle, 'group' => end($stack)->CMSTitle)), 'error');
             return false;
         }
         // Validate no pages
         if (empty($stack)) {
             $this->validationError('FormFields', _t("UserFormValidator.NO_PAGE", "Field '{name}' found before any pages", array('name' => $field->CMSTitle)), 'error');
             return false;
         }
         // Nest field group
         if ($field instanceof EditableFieldGroup) {
             $stack[] = $field;
             continue;
         }
         // Unnest field group
         if ($field instanceof EditableFieldGroupEnd) {
             $top = end($stack);
             // Check that the top is a group at all
             if (!$top instanceof EditableFieldGroup) {
                 $this->validationError('FormFields', _t("UserFormValidator.UNEXPECTED_GROUP_END", "'{name}' found without a matching group", array('name' => $field->CMSTitle)), 'error');
                 return false;
             }
             // Check that the top is the right group
             if ($top->EndID != $field->ID) {
                 $this->validationError('FormFields', _t("UserFormValidator.WRONG_GROUP_END", "'{name}' found closes the wrong group '{group}'", array('name' => $field->CMSTitle, 'group' => $top->CMSTitle)), 'error');
                 return false;
             }
             // Unnest group
             array_pop($stack);
         }
         // Normal field type
         if ($conditionalStep && $field->Required) {
             $this->validationError('FormFields', _t("UserFormValidator.CONDITIONAL_REQUIRED", "Required field '{name}' cannot be placed within a conditional page", array('name' => $field->CMSTitle)), 'error');
             return false;
         }
     }
     return true;
 }
 public function updateCMSFields(FieldList $fields)
 {
     $formID = $this->owner->FormID != 0 ? $this->owner->FormID : Session::get('CMSMain.currentPage');
     $formFields = EditableFormField::get()->filter('ParentID', (int) $formID);
     if ($formFields) {
         $source = $formFields->map('ID', 'Title');
         $fields->push(DropdownField::create('ConditionFieldID', 'Only send this email if the following field', $source)->setEmptyString('Select...'));
         $fields->push(TextField::create('ConditionFieldValue', '...has this value'));
     }
 }
    /**
     * Generate the javascript for the conditional field show / hiding logic.
     *
     * @return void
     */
    public function generateConditionalJavascript()
    {
        $default = "";
        $rules = "";
        $watch = array();
        $watchLoad = array();
        if ($this->Fields()) {
            foreach ($this->Fields() as $field) {
                $holderSelector = $field->getSelectorHolder();
                // Is this Field Show by Default
                if (!$field->ShowOnLoad) {
                    $default .= "{$holderSelector}.hide().trigger('userform.field.hide');\n";
                }
                // Check for field dependencies / default
                foreach ($field->DisplayRules() as $rule) {
                    // Get the field which is effected
                    $formFieldWatch = EditableFormField::get()->byId($rule->ConditionFieldID);
                    // Skip deleted fields
                    if (!$formFieldWatch) {
                        continue;
                    }
                    $fieldToWatch = $formFieldWatch->getSelectorField($rule);
                    $fieldToWatchOnLoad = $formFieldWatch->getSelectorField($rule, true);
                    // show or hide?
                    $view = $rule->Display == 'Hide' ? 'hide' : 'show';
                    $opposite = $view == "show" ? "hide" : "show";
                    // what action do we need to keep track of. Something nicer here maybe?
                    // @todo encapulsation
                    $action = "change";
                    if ($formFieldWatch instanceof EditableTextField) {
                        $action = "keyup";
                    }
                    // is this field a special option field
                    $checkboxField = false;
                    $radioField = false;
                    if (in_array($formFieldWatch->ClassName, array('EditableCheckboxGroupField', 'EditableCheckbox'))) {
                        $action = "click";
                        $checkboxField = true;
                    } else {
                        if ($formFieldWatch->ClassName == "EditableRadioField") {
                            $radioField = true;
                        }
                    }
                    // and what should we evaluate
                    switch ($rule->ConditionOption) {
                        case 'IsNotBlank':
                            $expression = $checkboxField || $radioField ? '$(this).is(":checked")' : '$(this).val() != ""';
                            break;
                        case 'IsBlank':
                            $expression = $checkboxField || $radioField ? '!($(this).is(":checked"))' : '$(this).val() == ""';
                            break;
                        case 'HasValue':
                            if ($checkboxField) {
                                $expression = '$(this).prop("checked")';
                            } else {
                                if ($radioField) {
                                    // We cannot simply get the value of the radio group, we need to find the checked option first.
                                    $expression = '$(this).parents(".field, .control-group").find("input:checked").val()=="' . $rule->FieldValue . '"';
                                } else {
                                    $expression = '$(this).val() == "' . $rule->FieldValue . '"';
                                }
                            }
                            break;
                        case 'ValueLessThan':
                            $expression = '$(this).val() < parseFloat("' . $rule->FieldValue . '")';
                            break;
                        case 'ValueLessThanEqual':
                            $expression = '$(this).val() <= parseFloat("' . $rule->FieldValue . '")';
                            break;
                        case 'ValueGreaterThan':
                            $expression = '$(this).val() > parseFloat("' . $rule->FieldValue . '")';
                            break;
                        case 'ValueGreaterThanEqual':
                            $expression = '$(this).val() >= parseFloat("' . $rule->FieldValue . '")';
                            break;
                        default:
                            // ==HasNotValue
                            if ($checkboxField) {
                                $expression = '!$(this).prop("checked")';
                            } else {
                                if ($radioField) {
                                    // We cannot simply get the value of the radio group, we need to find the checked option first.
                                    $expression = '$(this).parents(".field, .control-group").find("input:checked").val()!="' . $rule->FieldValue . '"';
                                } else {
                                    $expression = '$(this).val() != "' . $rule->FieldValue . '"';
                                }
                            }
                            break;
                    }
                    if (!isset($watch[$fieldToWatch])) {
                        $watch[$fieldToWatch] = array();
                    }
                    $watch[$fieldToWatch][] = array('expression' => $expression, 'holder_selector' => $holderSelector, 'view' => $view, 'opposite' => $opposite, 'action' => $action);
                    $watchLoad[$fieldToWatchOnLoad] = true;
                }
            }
        }
        if ($watch) {
            foreach ($watch as $key => $values) {
                $logic = array();
                $actions = array();
                foreach ($values as $rule) {
                    // Assign action
                    $actions[$rule['action']] = $rule['action'];
                    // Assign behaviour
                    $expression = $rule['expression'];
                    $holder = $rule['holder_selector'];
                    $view = $rule['view'];
                    // hide or show
                    $opposite = $rule['opposite'];
                    // Generated javascript for triggering visibility
                    $logic[] = <<<EOS
if({$expression}) {
\t{$holder}
\t\t.{$view}()
\t\t.trigger('userform.field.{$view}');
} else {
\t{$holder}
\t\t.{$opposite}()
\t\t.trigger('userform.field.{$opposite}');
}
EOS;
                }
                $logic = implode("\n", $logic);
                $rules .= $key . ".each(function() {\n\n\t\$(this).data('userformConditions', function() {\n\n\t\t{$logic}\n\n\t}); \n\n});\n";
                foreach ($actions as $action) {
                    $rules .= $key . ".{$action}(function() {\n\t\$(this).data('userformConditions').call(this);\n\n});\n";
                }
            }
        }
        if ($watchLoad) {
            foreach ($watchLoad as $key => $value) {
                $rules .= $key . ".each(function() {\n\t\$(this).data('userformConditions').call(this);\n\n});\n";
            }
        }
        // Only add customScript if $default or $rules is defined
        if ($default || $rules) {
            Requirements::customScript(<<<JS
\t\t\t\t(function(\$) {
\t\t\t\t\t\$(document).ready(function() {
\t\t\t\t\t\t{$default}

\t\t\t\t\t\t{$rules}
\t\t\t\t\t})
\t\t\t\t})(jQuery);
JS
, 'UserFormsConditional');
        }
    }
 /**
  * Generate a new non-conflicting Name value
  *
  * @return string
  */
 protected function generateName()
 {
     do {
         // Generate a new random name after this class
         $class = get_class($this);
         $entropy = substr(sha1(uniqid()), 0, 5);
         $name = "{$class}_{$entropy}";
         // Check if it conflicts
         $exists = EditableFormField::get()->filter('Name', $name)->count() > 0;
     } while ($exists);
     return $name;
 }
Beispiel #6
0
 /**
  * Return the html for a field option such as a 
  * dropdown field or a radio check box field
  *
  * @return bool|html
  */
 public function addoptionfield()
 {
     if (!SecurityToken::inst()->checkRequest($this->request)) {
         return $this->httpError(400);
     }
     // passed via the ajax
     $parent = isset($_REQUEST['Parent']) ? $_REQUEST['Parent'] : false;
     // work out the sort by getting the sort of the last field in the form +1
     if ($parent) {
         $sql_parent = (int) $parent;
         $parentObj = EditableFormField::get()->byID($parent);
         $optionClass = $parentObj && $parentObj->exists() ? $parentObj->getRelationClass('Options') : 'EditableOption';
         $sqlQuery = new SQLQuery();
         $sqlQuery = $sqlQuery->setSelect("MAX(\"Sort\")")->setFrom("\"EditableOption\"")->setWhere("\"ParentID\" = {$sql_parent}");
         $sort = $sqlQuery->execute()->value() + 1;
         if ($parent) {
             $object = Injector::inst()->create($optionClass);
             $object->write();
             $object->ParentID = $parent;
             $object->Sort = $sort;
             $object->Name = 'option' . $object->ID;
             $object->write();
             return $object->EditSegment();
         }
     }
     return false;
 }
 /**
  * Create or find an existing field with the matched specification
  *
  * @param EditableFormField $field
  * @param string $stage
  * @param string $conditionOption
  * @param string $display
  * @param string $conditionFieldName
  * @param string $value
  * @return EditableCustomRule
  */
 protected function findOrCreateRule(EditableFormField $field, $stage, $conditionOption, $display, $conditionFieldName, $value)
 {
     // Get id of field
     $conditionField = $conditionFieldName ? EditableFormField::get()->filter('Name', $conditionFieldName)->first() : null;
     // If live, search stage record for matching one
     if ($stage === 'Live') {
         $list = Versioned::get_by_stage('EditableCustomRule', 'Stage')->filter(array('ParentID' => $field->ID, 'ConditionFieldID' => $conditionField ? $conditionField->ID : 0, 'Display' => $display, 'ConditionOption' => $conditionOption));
         if ($value) {
             $list = $list->filter('FieldValue', $value);
         } else {
             $list = $list->where('"FieldValue" IS NULL OR "FieldValue" = \'\'');
         }
         $rule = $list->first();
         if ($rule) {
             $rule->write();
             $rule->publish("Stage", "Live");
             return $rule;
         }
     }
     // If none found, or in stage, create new record
     $rule = new EditableCustomRule();
     $rule->ParentID = $field->ID;
     $rule->ConditionFieldID = $conditionField ? $conditionField->ID : 0;
     $rule->Display = $display;
     $rule->ConditionOption = $conditionOption;
     $rule->FieldValue = $value;
     $rule->write();
     return $rule;
 }
 /**
  * @return void
  */
 public function onBeforeWrite()
 {
     parent::onBeforeWrite();
     if ($this->Name === 'Field') {
         throw new ValidationException('Field name cannot be "Field"');
     }
     if (!$this->Sort && $this->ParentID) {
         $parentID = $this->ParentID;
         $this->Sort = EditableFormField::get()->filter('ParentID', $parentID)->max('Sort') + 1;
     }
 }