/**
  * Creates a new HTMLEditorField.
  * @see TextareaField::__construct()
  *
  * @param string $name The internal field name, passed to forms.
  * @param string $title The human-readable field label.
  * @param mixed $value The value of the field.
  * @param string $config HTMLEditorConfig identifier to be used. Default to the active one.
  */
 public function __construct($name, $title = null, $value = '', $config = null)
 {
     parent::__construct($name, $title, $value);
     $this->editorConfig = $config ? $config : HtmlEditorConfig::get_active_identifier();
 }
 /**
  * Prepares everything just before rendering the field
  */
 protected function prepareForRender()
 {
     if (!$this->preparedForRender) {
         $this->preparedForRender = true;
         if (!$this->isReadonly() && $this->depth == 1) {
             // NOTE(Jake): jQuery.ondemand is required to allow FormField classes to add their own
             //             Requirements::javascript on-the-fly.
             //Requirements::javascript(FRAMEWORK_DIR . "/thirdparty/jquery/jquery.js");
             Requirements::css(MULTIRECORDEDITOR_DIR . '/css/MultiRecordField.css');
             if (is_subclass_of(Controller::curr(), 'LeftAndMain')) {
                 // NOTE(Jake): Only include in CMS to fix margin issues. Not in the main CSS file
                 //             so that the frontend CSS is less in the way.
                 Requirements::css(MULTIRECORDEDITOR_DIR . '/css/MultiRecordFieldCMS.css');
             }
             Requirements::css(THIRDPARTY_DIR . '/jquery-ui-themes/smoothness/jquery-ui.css');
             Requirements::javascript(FRAMEWORK_DIR . '/thirdparty/jquery-ui/jquery-ui.js');
             Requirements::javascript(FRAMEWORK_DIR . '/javascript/jquery-ondemand/jquery.ondemand.js');
             Requirements::javascript(THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js');
             Requirements::javascript(MULTIRECORDEDITOR_DIR . '/javascript/MultiRecordField.js');
             // If config is set to 'default' but 'default' isn't configured, fallback to 'cms'.
             // NOTE(Jake): In SS 3.2, 'default' is the default active config but its not configured.
             $availableConfigs = HtmlEditorConfig::get_available_configs_map();
             $activeIdentifier = HtmlEditorConfig::get_active_identifier();
             if ($activeIdentifier === 'default' && !isset($availableConfigs[$activeIdentifier])) {
                 HtmlEditorConfig::set_active('cms');
             }
         }
         //
         // Setup actions
         //
         $actions = $this->Actions();
         if ($actions && $actions->count()) {
             $modelClasses = $this->getModelClassesOrThrowExceptionIfEmpty();
             $modelFirstClass = key($modelClasses);
             $inlineAddButton = $actions->dataFieldByName('action_AddInlineRecord');
             if ($inlineAddButton) {
                 // Setup default inline field data attributes
                 //$inlineAddButton->setAttribute('data-name', $this->getName());
                 $inlineAddButton->setAttribute('data-action', $this->getName());
                 $inlineAddButton->setAttribute('data-class', $modelFirstClass);
                 $inlineAddButton->setAttribute('data-depth', $this->depth);
                 // Automatically apply all data attributes on this element, to the inline button.
                 foreach ($this->getAttributes() as $name => $value) {
                     if (substr($name, 0, 5) === 'data-') {
                         $inlineAddButton->setAttribute($name, $value);
                     }
                 }
                 if (count($modelClasses) == 1) {
                     $name = singleton($modelFirstClass)->i18n_singular_name();
                     $inlineAddButton->setTitle('Add ' . $name);
                 }
             }
             $classField = $actions->dataFieldByName('ClassName');
             if ($classField) {
                 if (count($modelClasses) > 1) {
                     if ($inlineAddButton) {
                         $inlineAddButton->setDisabled(true);
                     }
                     $classField->setSource($modelClasses);
                 } else {
                     $actions->removeByName('ClassName');
                 }
             }
             // Allow outside sources to influences the disable state class-wise
             if ($inlineAddButton && $inlineAddButton->isDisabled()) {
                 $inlineAddButton->addExtraClass('is-disabled');
             }
             //
             foreach ($actions as $actionField) {
                 // Expand out names
                 $actionField->setName($this->getName() . '_' . $actionField->getName());
             }
         }
         // Get existing records to add fields for
         $recordArray = array();
         if ($this->list && !$this->list instanceof UnsavedRelationList) {
             foreach ($this->list->toArray() as $record) {
                 $recordArray[$record->ID] = $record;
             }
         }
         //
         // If the user validation failed, Value() will be populated with some records
         // that have 'new_' IDs, so handle them.
         //
         $value = $this->Value();
         if ($value && is_array($value)) {
             foreach ($value as $class => $recordDatas) {
                 foreach ($recordDatas as $new_id => $fieldData) {
                     if (substr($new_id, 0, 4) === 'new_') {
                         $record = $class::create();
                         $record->MultiRecordField_NewID = $new_id;
                         $recordArray[$new_id] = $record;
                     } else {
                         if ($new_id == (string) (int) $new_id) {
                             // NOTE(Jake): "o-multirecordediting-1-id" == 0 // evaluates true in PHP 5.5.12,
                             //             So we need to make it a string again to avoid that dumb case.
                             $new_id = (int) $new_id;
                             if (!isset($recordArray[$new_id])) {
                                 throw new Exception('Record #' . $new_id . ' does not exist in this context.');
                             }
                             $record = $recordArray[$new_id];
                             //throw new Exception('todo, handle existing stuff that fails validation. ('.$new_id.')');
                         } else {
                             throw new Exception('Validation failed and unable to restore fields with invalid ID. (' . $new_id . ')');
                         }
                     }
                     // Update new/existing record with data
                     foreach ($fieldData as $fieldName => $fieldInfo) {
                         if (is_array($fieldInfo)) {
                             $record->{$fieldName} = $fieldInfo;
                         } else {
                             $record->{$fieldName} = $fieldInfo->value;
                         }
                     }
                 }
             }
         }
         // Transform into list
         $recordList = new ArrayList($recordArray);
         // Ensure all the records are sorted by the sort field
         $sortFieldName = $this->getSortFieldName();
         if ($sortFieldName) {
             $recordList = $recordList->sort($sortFieldName);
         }
         //
         // Return all fields from the records editing
         //
         foreach ($recordList as $record) {
             $recordFields = $this->getRecordDataFields($record);
             $this->applyUniqueFieldNames($recordFields, $record);
             foreach ($recordFields as $field) {
                 $this->children->push($field);
             }
         }
     }
 }