[FEATURE] Add possibility to store NULL values
authorOliver Hader <oliver@typo3.org>
Tue, 9 Oct 2012 18:17:43 +0000 (20:17 +0200)
committerOliver Hader <oliver.hader@typo3.org>
Sat, 10 Nov 2012 16:59:52 +0000 (17:59 +0100)
The current implementation in the TYPO3 backend does not allow
to store NULL values, only empty strings or zero as number are
allowed.
Since the overlay behavior of FAL takes e.g. the description
property from the original file object an empty value in the
disposal (the referenced file) cannot be defined to be blank,
thus not clearing the original file description.

For this case we need a new behavior to allow NULL values in
the storage and to handle that in the backend view.

This feature is enabled by adding "null" to the eval list of
the TCA configuration of a field, example:

'columns' => array(
  'title' => array(
    'config' => array(
      'type' => 'text',
      'eval' => 'null',
    )
  )
)

Besides that, of course the database field definition needs to
be updated to support NULL values.

Change-Id: Ib5cd0e34e34d084df7ba3380ae81e5240bcf76d6
Resolves: #41773
Releases: 6.0
Reviewed-on: http://review.typo3.org/15458
Reviewed-by: Oliver Hader
Tested-by: Oliver Hader
typo3/jsfunc.tbe_editor.js
typo3/sysext/backend/Classes/Controller/EditDocumentController.php
typo3/sysext/backend/Classes/Form/DataPreprocessor.php
typo3/sysext/backend/Classes/Form/FormEngine.php
typo3/sysext/core/Classes/DataHandling/DataHandler.php
typo3/sysext/core/Classes/Database/DatabaseConnection.php
typo3/sysext/t3skin/stylesheets/visual/element_tceforms.css
typo3/templates/tceforms.html

index 28e5c29..2c6df0f 100644 (file)
@@ -594,7 +594,20 @@ var TBE_EDITOR_str_replace = TBE_EDITOR.str_replace;
 
 
 var typo3form = {
+       fieldSetNull: function(fieldName, isNull) {
+               if (document[TBE_EDITOR.formname][fieldName]) {
+                       var formFieldItemWrapper = Element.up(document[TBE_EDITOR.formname][fieldName], '.t3-form-field-item');
+
+                       if (isNull) {
+                               formFieldItemWrapper.addClassName('disabled');
+                       } else {
+                               formFieldItemWrapper.removeClassName('disabled');
+                       }
+               }
+       },
        fieldSet: function(theField, evallist, is_in, checkbox, checkboxValue) {
+               var i;
+
                if (document[TBE_EDITOR.formname][theField]) {
                        var theFObj = new evalFunc_dummy (evallist,is_in, checkbox, checkboxValue);
                        var theValue = document[TBE_EDITOR.formname][theField].value;
@@ -605,6 +618,17 @@ var typo3form = {
                                document[TBE_EDITOR.formname][theField+"_hr"].value = evalFunc.outputObjValue(theFObj, theValue);
                                if (document[TBE_EDITOR.formname][theField+"_cb"])      document[TBE_EDITOR.formname][theField+"_cb"].checked = "on";
                        }
+
+                       var controlName = theField.replace(new RegExp('^' + TBE_EDITOR.prependFormFieldNames), 'control[active]');
+                       var controlFields = document[TBE_EDITOR.formname][controlName];
+
+                       if (controlFields) {
+                               for (i = 0; i < controlFields.length; i++) {
+                                       if (controlFields[i].type === 'checkbox' && !controlFields[i].checked) {
+                                               typo3form.fieldSetNull(theField, true);
+                                       }
+                               }
+                       }
                }
        },
        fieldGet: function(theField, evallist, is_in, checkbox, checkboxValue, checkbox_off, checkSetValue) {
index 6e73742..35ebe6b 100644 (file)
@@ -390,6 +390,7 @@ class EditDocumentController {
         */
        public function processData() {
                // GPvars specifically for processing:
+               $control = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('control');
                $this->data = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('data');
                $this->cmd = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('cmd');
                $this->mirror = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('mirror');
@@ -402,6 +403,10 @@ class EditDocumentController {
                /** @var $tce \TYPO3\CMS\Core\DataHandling\DataHandler */
                $tce = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\DataHandling\\DataHandler');
                $tce->stripslashes_values = 0;
+
+               if (!empty($control)) {
+                       $tce->setControl($control);
+               }
                if (isset($_POST['_translation_savedok_x'])) {
                        $tce->updateModeL10NdiffData = 'FORCE_FFUPD';
                }
index 20cf33b..9d9f746 100644 (file)
@@ -267,13 +267,14 @@ class DataPreprocessor {
                foreach ($copyOfColumns as $field => $fieldConfig) {
                        // Set $data variable for the field, either inputted value from $row - or if not found, the default value as defined in the "config" array
                        if (isset($row[$field])) {
-                               $data = $row[$field];
+                               $data = (string) $row[$field];
+                       } elseif (array_key_exists($field, $row) && !empty($fieldConfig['config']['eval']) && \TYPO3\CMS\Core\Utility\GeneralUtility::inList($fieldConfig['config']['eval'], 'null')) {
+                               $data = NULL;
                        } else {
-                               $data = $fieldConfig['config']['default'];
+                               $data = (string) $fieldConfig['config']['default'];
                        }
                        $data = $this->renderRecord_SW($data, $fieldConfig, $TSconfig, $table, $row, $field);
-                       // Set the field in the accumulation array IF the $data variabel is set:
-                       $totalRecordContent[$field] = isset($data) ? $data : '';
+                       $totalRecordContent[$field] = $data;
                }
                // Further processing may apply for each field in the record depending on the settings in the "types" configuration (the list of fields to currently display for a record in TCEforms).
                // For instance this could be processing instructions for the Rich Text Editor.
index e493842..ad613d2 100644 (file)
@@ -286,6 +286,13 @@ class FormEngine {
         */
        public $prependFormFieldNames_file = 'data_files';
 
+       /**
+        * The string to prepend form field names that are active (not NULL).
+        *
+        * @var string
+        */
+       protected $prependFormFieldNamesActive = 'control[active]';
+
        // The name attribute of the form.
        /**
         * @todo Define visibility
@@ -402,6 +409,13 @@ class FormEngine {
         */
        public $fieldTemplate = '<strong>###FIELD_NAME###</strong><br />###FIELD_ITEM###<hr />';
 
+       /**
+        * Template subpart for palette fields.
+        *
+        * @var string
+        */
+       protected $paletteFieldTemplate;
+
        // Wrapping template code for a section
        /**
         * @todo Define visibility
@@ -1007,6 +1021,9 @@ class FormEngine {
                                $PA['itemFormElName'] = $this->prependFormFieldNames . '[' . $table . '][' . $row['uid'] . '][' . $field . ']';
                                // Form field name, in case of file uploads
                                $PA['itemFormElName_file'] = $this->prependFormFieldNames_file . '[' . $table . '][' . $row['uid'] . '][' . $field . ']';
+                               // Form field name, to activate elements
+                               // If the "eval" list contains "null", elements can be deactivated which results in storing NULL to database
+                               $PA['itemFormElNameActive'] = $this->prependFormFieldNamesActive . '[' . $table . '][' . $row['uid'] . '][' . $field . ']';
                                // The value to show in the form field.
                                $PA['itemFormElValue'] = $row[$field];
                                $PA['itemFormElID'] = $this->prependFormFieldNames . '_' . $table . '_' . $row['uid'] . '_' . $field;
@@ -1096,7 +1113,8 @@ class FormEngine {
                                                        'ID' => $row['uid'],
                                                        'FIELD' => $field,
                                                        'TABLE' => $table,
-                                                       'ITEM' => $item
+                                                       'ITEM' => $item,
+                                                       'ITEM_NULLVALUE' => $this->renderNullValueWidget($table, $field, $row, $PA),
                                                );
                                                $out = $this->addUserTemplateMarkers($out, $table, $field, $row, $PA);
                                        } else {
@@ -1107,7 +1125,8 @@ class FormEngine {
                                                        'TABLE' => $table,
                                                        'ID' => $row['uid'],
                                                        'PAL_LINK_ICON' => $thePalIcon,
-                                                       'FIELD' => $field
+                                                       'FIELD' => $field,
+                                                       'ITEM_NULLVALUE' => $this->renderNullValueWidget($table, $field, $row, $PA),
                                                );
                                                $out = $this->addUserTemplateMarkers($out, $table, $field, $row, $PA);
                                                // String:
@@ -1347,6 +1366,58 @@ function ' . $evalData . '(value) {
        }
 
        /**
+        * Renders a view widget to handle and activate NULL values.
+        * The widget is enabled by using 'null' in the 'eval' TCA definition.
+        *
+        * @param string $table Name of the table
+        * @param string $field Name of the field
+        * @param array $row Accordant data of the record row
+        * @param array $PA Parameters array with rendering instructions
+        * @return string Widget (if any).
+        */
+       protected function renderNullValueWidget($table, $field, array $row, array $PA) {
+               $widget = '';
+
+               $config = $PA['fieldConf']['config'];
+               if (!empty($config['eval']) && \TYPO3\CMS\Core\Utility\GeneralUtility::inList($config['eval'], 'null')) {
+                       $isNull = ($PA['itemFormElValue'] === NULL);
+
+                       $checked = ($isNull ? '' : ' checked="checked"');
+                       $onChange = htmlspecialchars(
+                               'typo3form.fieldSetNull(\'' . $PA['itemFormElName'] . '\', !this.checked)'
+                       );
+
+                       $widget = '<span class="t3-tceforms-widget-null-wrapper">' .
+                               '<input type="hidden" name="' . $PA['itemFormElNameActive'] . '" value="0" />' .
+                               '<input type="checkbox" name="' . $PA['itemFormElNameActive'] . '" value="1" onchange="' . $onChange . '"' . $checked . ' />' .
+                       '</span>';
+               }
+
+               return $widget;
+       }
+
+       /**
+        * Determines whether the current field value is considered as NULL value.
+        * Using NULL values is enabled by using 'null' in the 'eval' TCA definition.
+        *
+        * @param string $table Name of the table
+        * @param string $field Name of the field
+        * @param array $row Accordant data
+        * @param array $PA Parameters array with rendering instructions
+        * @return boolean
+        */
+       protected function isNullValue($table, $field, array $row, array $PA) {
+               $result = FALSE;
+
+               $config = $PA['fieldConf']['config'];
+               if ($PA['itemFormElValue'] === NULL && !empty($config['eval']) && \TYPO3\CMS\Core\Utility\GeneralUtility::inList($config['eval'], 'null')) {
+                       $result = TRUE;
+               }
+
+               return $result;
+       }
+
+       /**
         * Generation of TCEform elements of the type "text"
         * This will render a <textarea> OR RTE area form field, possibly with various control/validation features
         *
@@ -4752,6 +4823,7 @@ function ' . $evalData . '(value) {
                $this->totalWrap = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($template, '###TOTALWRAP###');
                // Wrapping a single field:
                $this->fieldTemplate = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($template, '###FIELDTEMPLATE###');
+               $this->paletteFieldTemplate = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($template, '###PALETTEFIELDTEMPLATE###');
                $this->palFieldTemplate = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($template, '###PALETTE_FIELDTEMPLATE###');
                $this->palFieldTemplateHeader = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($template, '###PALETTE_FIELDTEMPLATE_HEADER###');
                $this->sectionWrap = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($template, '###SECTION_WRAP###');
@@ -4989,8 +5061,23 @@ function ' . $evalData . '(value) {
                                }
                        } else {
                                $lastLineWasLinebreak = FALSE;
-                               $fieldIdentifierForJs = $content['TABLE'] . '_' . $content['ID'] . '_' . $content['FIELD'];
-                               $iRow[$row][] = '<span class="t3-form-palette-field-container">' . '<label' . $labelAttributes . '>' . $content['NAME'] . '</label>' . '<span' . $fieldAttributes . '>' . '<img name="cm_' . $fieldIdentifierForJs . '" src="clear.gif" class="t3-form-palette-icon-contentchanged" alt="" />' . '<img name="req_' . $fieldIdentifierForJs . '" src="clear.gif" class="t3-form-palette-icon-required" alt="" />' . $content['ITEM'] . '</span>' . '</span>';
+
+                               $paletteMarkers = array(
+                                       '###CONTENT_TABLE###' => $content['TABLE'],
+                                       '###CONTENT_ID###' => $content['ID'],
+                                       '###CONTENT_FIELD###' => $content['FIELD'],
+                                       '###CONTENT_NAME###' => $content['NAME'],
+                                       '###CONTENT_ITEM###' => $content['ITEM'],
+                                       '###CONTENT_ITEM_NULLVALUE###' => $content['ITEM_NULLVALUE'],
+                                       '###ATTRIBUTES_LABEL###' => $labelAttributes,
+                                       '###ATTRIBUTES_FIELD###' => $fieldAttributes,
+                               );
+                               $iRow[$row][] = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray(
+                                       $this->paletteFieldTemplate,
+                                       $paletteMarkers,
+                                       FALSE,
+                                       TRUE
+                               );
                        }
                }
                // Final wrapping into the fieldset:
index 48279d7..ae07c0c 100644 (file)
@@ -298,6 +298,14 @@ class DataHandler {
         */
        public $exclude_array;
 
+       /**
+        * Data submitted from the form view, used to control behaviours,
+        * e.g. this is used to activate/deactive fields and thus store NULL values
+        *
+        * @var array
+        */
+       protected $control = array();
+
        // Set with incoming data array
        /**
         * @todo Define visibility
@@ -490,6 +498,13 @@ class DataHandler {
        protected $outerMostInstance = NULL;
 
        /**
+        * @param array $control
+        */
+       public function setControl(array $control) {
+               $this->control = $control;
+       }
+
+       /**
         * Initializing.
         * For details, see 'TYPO3 Core API' document.
         * This function does not start the processing of data, but merely initializes the object
@@ -705,6 +720,8 @@ class DataHandler {
         * @return void
         */
        public function process_datamap() {
+               $this->controlActiveElements();
+
                // Keep versionized(!) relations here locally:
                $registerDBList = array();
                $this->registerElementsToBeDeleted();
@@ -1216,7 +1233,7 @@ class DataHandler {
                                                if (isset($GLOBALS['TCA'][$table]['columns'][$field])) {
                                                        // Evaluating the value
                                                        $res = $this->checkValue($table, $field, $fieldValue, $id, $status, $realPid, $tscPID);
-                                                       if (isset($res['value'])) {
+                                                       if (array_key_exists('value', $res)) {
                                                                $fieldArray[$field] = $res['value'];
                                                        }
                                                        // Add the value of the original record to the diff-storage content:
@@ -1383,6 +1400,12 @@ class DataHandler {
         * @todo Define visibility
         */
        public function checkValue_SW($res, $value, $tcaFieldConf, $table, $id, $curValue, $status, $realPid, $recFID, $field, $uploadedFiles, $tscPID, array $additionalData = NULL) {
+               // Convert to NULL value if defined in TCA
+               if ($value === NULL && !empty($tcaFieldConf['eval']) && \TYPO3\CMS\Core\Utility\GeneralUtility::inList($tcaFieldConf['eval'], 'null')) {
+                       $res = array('value' => NULL);
+                       return $res;
+               }
+
                $PP = array($table, $id, $curValue, $status, $realPid, $recFID, $tscPID);
                switch ($tcaFieldConf['type']) {
                case 'text':
@@ -6001,7 +6024,12 @@ class DataHandler {
                        $GLOBALS['TYPO3_DB']->sql_free_result($res);
                        // Unset the fields which are similar:
                        foreach ($fieldArray as $col => $val) {
-                               if (!$GLOBALS['TCA'][$table]['columns'][$col]['config']['MM'] && (!strcmp($val, $currentRecord[$col]) || $cRecTypes[$col] == 'int' && $currentRecord[$col] == 0 && !strcmp($val, ''))) {
+                               $isAlreadyNull = ($val === NULL && $currentRecord[$col] === NULL);
+                               $isNotNull = ($val !== NULL);
+                               // Unset field values if they are empty, which is "0" for integer types and "" for string - except the current field holds MM relations.
+                               // If NULL values shall be stored, then the value will only be unset if the current stored value is already NULL.
+                               // In general this avoids to store superfluous data which also will be visualized in the editing history.
+                               if (!$GLOBALS['TCA'][$table]['columns'][$col]['config']['MM'] && ($isAlreadyNull || $isNotNull && (!strcmp($val, $currentRecord[$col]) || $cRecTypes[$col] == 'int' && $currentRecord[$col] == 0 && !strcmp($val, '')))) {
                                        unset($fieldArray[$col]);
                                } else {
                                        if (!isset($this->mmHistoryRecords[($table . ':' . $id)]['oldRecord'][$col])) {
@@ -7070,6 +7098,46 @@ class DataHandler {
                return $elements;
        }
 
+       /**
+        * Controls active elements and sets NULL values if not active.
+        * Datamap is modified accordant to submitted control values.
+        *
+        * @return void
+        */
+       protected function controlActiveElements() {
+               if (!empty($this->control['active'])) {
+                       $this->setNullValues(
+                               $this->control['active'],
+                               $this->datamap
+                       );
+               }
+       }
+
+       /**
+        * Sets NULL values in haystack array.
+        * The general behaviour in the user interface is to enable/activate fields.
+        * Thus, this method uses NULL as value to be stored if a field is not active.
+        *
+        * @param array $active Hierarchical array with active elements
+        * @param array $haystack Hierachical array with haystack to be modified
+        * @return void
+        */
+       protected function setNullValues(array $active, array &$haystack) {
+               foreach ($active as $key => $value) {
+                       // Nested data is processes recursively
+                       if (is_array($value)) {
+                               $this->setNullValues(
+                                       $value,
+                                       $haystack[$key]
+                               );
+                       // Field has not been activated in the user interface,
+                       // thus a NULL value shall be stored in the database
+                       } elseif ($value == 0) {
+                               $haystack[$key] = NULL;
+                       }
+               }
+       }
+
 }
 
 
index ade8e0d..19b3274 100644 (file)
@@ -455,7 +455,7 @@ class DatabaseConnection {
                        $fields = array();
                        if (is_array($fields_values) && count($fields_values)) {
                                // Quote and escape values
-                               $nArr = $this->fullQuoteArray($fields_values, $table, $no_quote_fields);
+                               $nArr = $this->fullQuoteArray($fields_values, $table, $no_quote_fields, TRUE);
                                foreach ($nArr as $k => $v) {
                                        $fields[] = $k . '=' . $v;
                                }
@@ -678,11 +678,16 @@ class DatabaseConnection {
         *
         * @param string $str Input string
         * @param string $table Table name for which to quote string. Just enter the table that the field-value is selected from (and any DBAL will look up which handler to use and then how to quote the string!).
+        * @param boolean $allowNull Whether to allow NULL values
         * @return string Output string; Wrapped in single quotes and quotes in the string (" / ') and \ will be backslashed (or otherwise based on DBAL handler)
         * @see quoteStr()
         * @todo Define visibility
         */
-       public function fullQuoteStr($str, $table) {
+       public function fullQuoteStr($str, $table, $allowNull = FALSE) {
+               if ($allowNull && $str === NULL) {
+                       return 'NULL';
+               }
+
                return '\'' . mysql_real_escape_string($str, $this->link) . '\'';
        }
 
@@ -692,11 +697,12 @@ class DatabaseConnection {
         * @param array $arr Array with values (either associative or non-associative array)
         * @param string $table Table name for which to quote
         * @param string/array $noQuote List/array of keys NOT to quote (eg. SQL functions) - ONLY for associative arrays
+        * @param boolean $allowNull Whether to allow NULL values
         * @return array The input array with the values quoted
         * @see cleanIntArray()
         * @todo Define visibility
         */
-       public function fullQuoteArray($arr, $table, $noQuote = FALSE) {
+       public function fullQuoteArray($arr, $table, $noQuote = FALSE, $allowNull = FALSE) {
                if (is_string($noQuote)) {
                        $noQuote = explode(',', $noQuote);
                } elseif (!is_array($noQuote)) {
@@ -704,7 +710,7 @@ class DatabaseConnection {
                }
                foreach ($arr as $k => $v) {
                        if ($noQuote === FALSE || !in_array($k, $noQuote)) {
-                               $arr[$k] = $this->fullQuoteStr($v, $table);
+                               $arr[$k] = $this->fullQuoteStr($v, $table, $allowNull);
                        }
                }
                return $arr;
index 4da1a09..c1dace6 100644 (file)
@@ -37,13 +37,18 @@ table#typo3-altdoc-header input,
 .t3-tceforms-input-wrapper,
 .t3-tceforms-input-wrapper-hover,
 .t3-tceforms-input-wrapper-datetime,
-.t3-tceforms-input-wrapper-datetime-hover {
+.t3-tceforms-input-wrapper-datetime-hover,
+.t3-tceforms-widget-null-wrapper {
        display: block;
        float: left;
        position: relative;
 }
 
 
+.t3-tceforms-widget-null-wrapper {
+       margin-right: 5px;
+}
+
 
 .t3-tceforms-input-wrapper .t3-tceforms-input-clearer,
 .t3-tceforms-input-wrapper-hover .t3-tceforms-input-clearer {
@@ -492,4 +497,31 @@ TCEforms Sections
     position:absolute;
     right:3px;
     top:4px;
+}
+
+.t3-form-field-item {
+       position: relative;
+       display: inline-block;
+       border: 1px solid transparent;
+}
+
+.t3-form-field-item.disabled {
+       border: 1px dotted #696362;
+}
+
+.t3-form-field-disable,
+.t3-form-field-item.disabled .t3-form-field-item.disabled .t3-form-field-disable {
+       display: none;
+}
+.t3-form-field-item.disabled .t3-form-field-disable {
+       z-index: 3000;
+       background: #f4f4f4;
+       display: inline-block;
+       position: absolute;
+       width: 100%;
+       height: 100%;
+
+       opacity: 0.5;
+       filter: alpha(opacity=50);
+       -moz-opacity: 0.5;
 }
\ No newline at end of file
index 5acac3c..20f31ba 100644 (file)
        <td colspan="2" class="formField-header"><span style="color:###FONTCOLOR_HEAD###;"###CLASSATTR_4###><strong>###FIELD_NAME###</strong></span></td>
 </tr>
 <tr ###BGCOLOR######CLASSATTR_1###>
-       <td colspan="2" class="formField-field" valign="top"><span class="t3-form-field-container"><img name="cm_###FIELD_TABLE###_###FIELD_ID###_###FIELD_FIELD###" src="clear.gif" class="t3-TCEforms-contentchangedImg" alt="" /><img name="req_###FIELD_TABLE###_###FIELD_ID###_###FIELD_FIELD###" src="clear.gif" class="t3-TCEforms-reqImg" alt="" />###FIELD_ITEM######FIELD_PAL_LINK_ICON###</span></td>
+       <td colspan="2" class="formField-field" valign="top">
+               <span class="t3-form-field-container">
+                       <img name="cm_###FIELD_TABLE###_###FIELD_ID###_###FIELD_FIELD###" src="clear.gif" class="t3-TCEforms-contentchangedImg" alt="" />
+                       <img name="req_###FIELD_TABLE###_###FIELD_ID###_###FIELD_FIELD###" src="clear.gif" class="t3-TCEforms-reqImg" alt="" />
+                       ###FIELD_ITEM_NULLVALUE###
+                       <div class="t3-form-field-item">
+                               <div class="t3-form-field-disable"></div>
+                               ###FIELD_ITEM###
+                       </div>
+                       ###FIELD_PAL_LINK_ICON###
+               </span>
+       </td>
 </tr>
 <!-- ###FIELDTEMPLATE### end -->
 
 
+<!-- ###PALETTEFIELDTEMPLATE### begin -->
+<span class="t3-form-palette-field-container">
+       <label###ATTRIBUTES_LABEL###>
+               ###CONTENT_NAME###
+       </label>
+       <span###ATTRIBUTES_FIELD###>
+               <img name="cm_###CONTENT_TABLE###_###CONTENT_ID###_###CONTENT_FIELD###" src="clear.gif" class="t3-form-palette-icon-contentchanged" alt="" />
+               <img name="req_###CONTENT_TABLE###_###CONTENT_ID###_###CONTENT_FIELD###" src="clear.gif" class="t3-form-palette-icon-required" alt="" />
+               ###CONTENT_ITEM_NULLVALUE###
+               <div class="t3-form-field-item">
+                       <div class="t3-form-field-disable"></div>
+                       ###CONTENT_ITEM###
+               </div>
+       </span>
+</span>
+<!-- ###PALETTEFIELDTEMPLATE### end -->
+
+
 <!-- ###PALETTE_FIELDTEMPLATE### begin -->
 <tr ###BGCOLOR######CLASSATTR_1###>
        <td colspan="2" nowrap="nowrap" valign="top">###FIELD_PALETTE###</td>