Fixed issue #17284: Formprotection persistToken method is called too often, causing...
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_frontendedit.php
index 4c41d65..64a2e44 100644 (file)
@@ -1,30 +1,30 @@
 <?php
 /***************************************************************
-*  Copyright notice
-*
-*  (c) 2008 Jeff Segars <jeff@webempoweredchurch.org>
-*  (c) 2008 David Slayback <dave@webempoweredchurch.org>
-*  All rights reserved
-*
-*  This script is part of the TYPO3 project. The TYPO3 project is
-*  free software; you can redistribute it and/or modify
-*  it under the terms of the GNU General Public License as published by
-*  the Free Software Foundation; either version 2 of the License, or
-*  (at your option) any later version.
-*
-*  The GNU General Public License can be found at
-*  http://www.gnu.org/copyleft/gpl.html.
-*  A copy is found in the textfile GPL.txt and important notices to the license
-*  from the author is found in LICENSE.txt distributed with these scripts.
-*
-*
-*  This script is distributed in the hope that it will be useful,
-*  but WITHOUT ANY WARRANTY; without even the implied warranty of
-*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-*  GNU General Public License for more details.
-*
-*  This copyright notice MUST APPEAR in all copies of the script!
-***************************************************************/
+ *  Copyright notice
+ *
+ *  (c) 2008-2011 Jeff Segars <jeff@webempoweredchurch.org>
+ *  (c) 2008-2011 David Slayback <dave@webempoweredchurch.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
 /**
  * Controller class for frontend editing.
  *
  * @subpackage t3lib
  */
 class t3lib_frontendedit {
-
-       /**
-        * TCEmain object.
-        *
-        * @var t3lib_tcemain
-        */
-       protected $tce;
-
-
        /**
-        * Force preview?
+        * GET/POST parameters for the FE editing.
+        * Accessed as $GLOBALS['BE_USER']->frontendEdit->TSFE_EDIT, thus public
         *
-        * @var boolean
+        * @var array
         */
-       protected $ext_forcePreview = false;
+       public $TSFE_EDIT;
 
        /**
-        * Comma separated list of page UIDs to be published.
-        *
-        * @var string
-        */
-       protected $extPublishList = '';
-
-       /**
-        * Creates and initializes the TCEmain object.
+        * TCEmain object.
         *
-        * @return      void
+        * @var t3lib_tcemain
         */
-       public function __construct() {
-               $this->tce = t3lib_div::makeInstance('t3lib_TCEmain');
-               $this->tce->stripslashes_values=0;
-       }
+       protected $tce;
 
        /**
         * Initializes configuration options.
@@ -75,76 +57,17 @@ class t3lib_frontendedit {
         * @return      void
         */
        public function initConfigOptions() {
-               $this->saveConfigOptions();
-               $this->TSFE_EDIT = t3lib_div::_POST('TSFE_EDIT');
-
-                       // Setting some values based on the admin panel
-               $GLOBALS['TSFE']->forceTemplateParsing = $this->extGetFeAdminValue('tsdebug', 'forceTemplateParsing');
-               $GLOBALS['TSFE']->displayEditIcons = $this->extGetFeAdminValue('edit', 'displayIcons');
-               $GLOBALS['TSFE']->displayFieldEditIcons = $this->extGetFeAdminValue('edit', 'displayFieldIcons');
-
-               if ($this->extGetFeAdminValue('tsdebug', 'displayQueries')) {
-                       if ($GLOBALS['TYPO3_DB']->explainOutput == 0) {         // do not override if the value is already set in t3lib_db
-                                       // Enable execution of EXPLAIN SELECT queries
-                               $GLOBALS['TYPO3_DB']->explainOutput = 3;
-                       }
-               }
-
-               if (t3lib_div::_GP('ADMCMD_editIcons')) {
-                       $GLOBALS['TSFE']->displayFieldEditIcons=1;
-                       $GLOBALS['BE_USER']->uc['TSFE_adminConfig']['edit_editNoPopup']=1;
-               }
-
-               if (t3lib_div::_GP('ADMCMD_simUser')) {
-                       $GLOBALS['BE_USER']->uc['TSFE_adminConfig']['preview_simulateUserGroup']=intval(t3lib_div::_GP('ADMCMD_simUser'));
-                       $this->ext_forcePreview = true;
-               }
-
-               if (t3lib_div::_GP('ADMCMD_simTime')) {
-                       $GLOBALS['BE_USER']->uc['TSFE_adminConfig']['preview_simulateDate']=intval(t3lib_div::_GP('ADMCMD_simTime'));
-                       $this->ext_forcePreview = true;
-               }
+               $this->TSFE_EDIT = t3lib_div::_GP('TSFE_EDIT');
 
                        // Include classes for editing IF editing module in Admin Panel is open
-               if (($this->isAdminModuleEnabled('edit') && $this->isAdminModuleOpen('edit')) || $GLOBALS['TSFE']->displayEditIcons == 1) {
+               if ($GLOBALS['BE_USER']->isFrontendEditingActive()) {
                        $GLOBALS['TSFE']->includeTCA();
                        if ($this->isEditAction()) {
-                               require_once (PATH_t3lib . 'class.t3lib_tcemain.php');
                                $this->editAction();
                        }
-
-                       if ($this->isEditFormShown()) {
-                               require_once(PATH_t3lib . 'class.t3lib_tceforms.php');
-                               require_once(PATH_t3lib . 'class.t3lib_iconworks.php');
-                               require_once(PATH_t3lib . 'class.t3lib_loaddbgroup.php');
-                               require_once(PATH_t3lib . 'class.t3lib_transferdata.php');
-                       }
-               }
-
-               if ($GLOBALS['TSFE']->forceTemplateParsing || $GLOBALS['TSFE']->displayEditIcons || $GLOBALS['TSFE']->displayFieldEditIcons) {
-                       $GLOBALS['TSFE']->set_no_cache();
                }
        }
 
-
-       /**
-        * Delegates to the appropriate view and renders the admin panel content.
-        *
-        * @return      string.
-        */
-       public function displayAdmin() {
-               $content = '';
-               $adminClass = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/classes/class.frontendedit.php']['admin'];
-               if ($adminClass && !$GLOBALS['BE_USER']->extAdminConfig['hide'] && $GLOBALS['TSFE']->config['config']['admPanel']) {
-                       $admin = &t3lib_div::getUserObj($adminClass);
-                       if (is_object($admin)) {
-                               $content =  $admin->display();
-                       }
-               }
-
-               return $content;
-       }
-
        /**
         * Generates the "edit panels" which can be shown for a page or records on a page when the Admin Panel is enabled for a backend users surfing the frontend.
         * With the "edit panel" the user will see buttons with links to editing, moving, hiding, deleting the element
@@ -161,6 +84,9 @@ class t3lib_frontendedit {
                if ($conf['newRecordFromTable']) {
                        $currentRecord = $conf['newRecordFromTable'] . ':NEW';
                        $conf['allow'] = 'new';
+                       $checkEditAccessInternals = FALSE;
+               } else {
+                       $checkEditAccessInternals = TRUE;
                }
 
                list($table, $uid) = explode(':', $currentRecord);
@@ -168,13 +94,13 @@ class t3lib_frontendedit {
                        // Page ID for new records, 0 if not specified
                $newRecordPid = intval($conf['newRecordInPid']);
                if (!$conf['onlyCurrentPid'] || $dataArray['pid'] == $GLOBALS['TSFE']->id) {
-                       if ($table=='pages') {
+                       if ($table == 'pages') {
                                $newUid = $uid;
                        } else {
                                if ($conf['newRecordFromTable']) {
                                        $newUid = $GLOBALS['TSFE']->id;
                                        if ($newRecordPid) {
-                                                $newUid = $newRecordPid;
+                                               $newUid = $newRecordPid;
                                        }
                                } else {
                                        $newUid = -1 * $uid;
@@ -182,13 +108,13 @@ class t3lib_frontendedit {
                        }
                }
 
-               if ($GLOBALS['TSFE']->displayEditIcons && $table && $this->allowedToEdit($table, $dataArray, $conf) && $this->allowedToEditLanguage($table, $dataArray)) {
+               if ($GLOBALS['TSFE']->displayEditIcons && $table && $this->allowedToEdit($table, $dataArray, $conf, $checkEditAccessInternals) && $this->allowedToEditLanguage($table, $dataArray)) {
                        $editClass = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/classes/class.frontendedit.php']['edit'];
                        if ($editClass) {
-                               $edit = &t3lib_div::getUserObj($editClass, false);
+                               $edit = t3lib_div::getUserObj($editClass, FALSE);
                                if (is_object($edit)) {
                                        $allowedActions = $this->getAllowedEditActions($table, $conf, $dataArray['pid']);
-                                       $content = $edit->editPanel($content, $conf, $currentRecord, $dataArray, $table, $allowedActions, $newUid, $this->getHiddenFieldArray($dataArray));
+                                       $content = $edit->editPanel($content, $conf, $currentRecord, $dataArray, $table, $allowedActions, $newUid, $this->getHiddenFields($dataArray));
                                }
                        }
                }
@@ -197,18 +123,6 @@ class t3lib_frontendedit {
        }
 
        /**
-        * Gets the hidden fields (array key=field name, value=field value) to be used in the edit panel for a particular content element. 
-        * In the normal case, no hidden fields are needed but special controllers such as TemplaVoila need to track flexform pointers, etc.
-        *
-        * @param       array   The data array for a specific content element.
-        * @return      array
-        */
-       public function getHiddenFieldArray(array $dataArray) {
-                       // No special hidden fields needed.
-               return array();
-       }
-
-       /**
         * Adds an edit icon to the content string. The edit icon links to alt_doc.php with proper parameters for editing the table/fields of the context.
         * This implements TYPO3 context sensitive editing facilities. Only backend users will have access (if properly configured as well).
         *
@@ -221,29 +135,29 @@ class t3lib_frontendedit {
         * @return      string          The input content string, possibly with edit icons added (not necessarily in the end but just after the last string of normal content.
         */
 
-       public function displayEditIcons($content, $params, array $conf=array(), $currentRecord = '', array $dataArray = array(), $addUrlParamStr = '') {
+       public function displayEditIcons($content, $params, array $conf = array(), $currentRecord = '', array $dataArray = array(), $addUrlParamStr = '') {
                        // Check incoming params:
                list($currentRecordTable, $currentRecordUID) = explode(':', $currentRecord);
                list($fieldList, $table) = array_reverse(t3lib_div::trimExplode(':', $params, 1)); // Reverse the array because table is optional
                if (!$table) {
                        $table = $currentRecordTable;
                } elseif ($table != $currentRecordTable) {
-                               return $content;        // If the table is set as the first parameter, and does not match the table of the current record, then just return.
+                       return $content; // If the table is set as the first parameter, and does not match the table of the current record, then just return.
                }
 
                $editUid = $dataArray['_LOCALIZED_UID'] ? $dataArray['_LOCALIZED_UID'] : $currentRecordUID;
 
                        // Edit icons imply that the editing action is generally allowed, assuming page and content element permissions permit it.
-               if(!array_key_exists('allow', $conf)) {
+               if (!array_key_exists('allow', $conf)) {
                        $conf['allow'] = 'edit';
                }
 
                if ($GLOBALS['TSFE']->displayFieldEditIcons && $table && $this->allowedToEdit($table, $dataArray, $conf) && $fieldList && $this->allowedToEditLanguage($table, $dataArray)) {
                        $editClass = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/classes/class.frontendedit.php']['edit'];
                        if ($editClass) {
-                               $edit = &t3lib_div::getUserObj($editClass);
+                               $edit = t3lib_div::getUserObj($editClass);
                                if (is_object($edit)) {
-                                       $content = $edit->editIcons($content, $params, $conf, $currentRecord, $dataArray, $addURLParamStr, $table, $editUid, $fieldList);
+                                       $content = $edit->editIcons($content, $params, $conf, $currentRecord, $dataArray, $addUrlParamStr, $table, $editUid, $fieldList);
                                }
                        }
                }
@@ -251,142 +165,6 @@ class t3lib_frontendedit {
                return $content;
        }
 
-       /**
-        * Checks if a Admin Panel section ("module") is available for the user. If so, true is returned.
-        *
-        * @param       string          The module key, eg. "edit", "preview", "info" etc.
-        * @return      boolean
-        */
-       public function isAdminModuleEnabled($key) {
-                       // Returns true if the module checked is "preview" and the forcePreview flag is set.
-               if ($key=='preview' && $this->ext_forcePreview) {
-                       return true;
-               }
-
-                       // If key is not set, only "all" is checked
-               if ($GLOBALS['BE_USER']->extAdminConfig['enable.']['all']) {
-                       return true;
-               }
-
-               if ($GLOBALS['BE_USER']->extAdminConfig['enable.'][$key]) {
-                       return true;
-               }
-       }
-
-       /**
-        * Saves any change in settings made in the Admin Panel.
-        * Called from index_ts.php right after access check for the Admin Panel
-        *
-        * @return      void
-        */
-       public function saveConfigOptions() {
-               $input = t3lib_div::_GP('TSFE_ADMIN_PANEL');
-               if (is_array($input)) {
-                               // Setting
-                       $GLOBALS['BE_USER']->uc['TSFE_adminConfig'] = array_merge(!is_array($GLOBALS['BE_USER']->uc['TSFE_adminConfig']) ? array() : $GLOBALS['BE_USER']->uc['TSFE_adminConfig'], $input);                      // Candidate for t3lib_div::array_merge() if integer-keys will some day make trouble...
-                       unset($GLOBALS['BE_USER']->uc['TSFE_adminConfig']['action']);
-
-                               // Actions:
-                       if ($input['action']['clearCache'] && $this->isAdminModuleEnabled('cache')) {
-                               $GLOBALS['BE_USER']->extPageInTreeInfo=array();
-                               $theStartId = intval($input['cache_clearCacheId']);
-                               $GLOBALS['TSFE']->clearPageCacheContent_pidList($GLOBALS['BE_USER']->extGetTreeList($theStartId, $this->extGetFeAdminValue('cache', 'clearCacheLevels'), 0, $GLOBALS['BE_USER']->getPagePermsClause(1)) . $theStartId);
-                       }
-                       if ($input['action']['publish'] && $this->isAdminModuleEnabled('publish')) {
-                               $theStartId = intval($input['publish_id']);
-                               $this->extPublishList = $GLOBALS['BE_USER']->extGetTreeList($theStartId, $this->extGetFeAdminValue('publish', 'levels'), 0, $GLOBALS['BE_USER']->getPagePermsClause(1)) . $theStartId;
-                       }
-
-                               // Saving
-                       $GLOBALS['BE_USER']->writeUC();
-               }
-               $GLOBALS['TT']->LR = $this->extGetFeAdminValue('tsdebug', 'LR');
-
-               if ($this->extGetFeAdminValue('cache', 'noCache')) {
-                       $GLOBALS['TSFE']->set_no_cache();
-               }
-
-                       // Hook for post processing the frontend admin configuration. Added with TYPO3 4.2, so naming is now incorrect but preserves compatibility.
-                       // @deprecated  since TYPO3 4.3
-               if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['extSaveFeAdminConfig-postProc'])) {
-                       $_params = array('input' => &$input, 'pObj' => &$this);
-                       foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['extSaveFeAdminConfig-postProc'] as $_funcRef) {
-                               t3lib_div::callUserFunction($_funcRef, $_params, $this);
-                       }
-               }
-       }
-
-       /**
-        * Returns the value for a Admin Panel setting. You must specify both the module-key and the internal setting key.
-        *
-        * @param       string          Module key
-        * @param       string          Setting key
-        * @return      string          The setting value
-        */
-       public function extGetFeAdminValue($pre, $val='') {
-                       // Check if module is enabled.
-               if ($this->isAdminModuleEnabled($pre)) {
-                               // Exceptions where the values can be overridden from backend:
-                               // deprecated
-                       if ($pre . '_' . $val == 'edit_displayIcons' && $GLOBALS['BE_USER']->extAdminConfig['module.']['edit.']['forceDisplayIcons']) {
-                               return true;
-                       }
-                       if ($pre . '_' . $val == 'edit_displayFieldIcons' && $GLOBALS['BE_USER']->extAdminConfig['module.']['edit.']['forceDisplayFieldIcons']) {
-                               return true;
-                       }
-
-                               // override all settings with user TSconfig
-                       if ($GLOBALS['BE_USER']->extAdminConfig['override.'][$pre . '.'][$val] && $val) {
-                               return $GLOBALS['BE_USER']->extAdminConfig['override.'][$pre . '.'][$val];
-                       }
-                       if ($GLOBALS['BE_USER']->extAdminConfig['override.'][$pre]) {
-                               return $GLOBALS['BE_USER']->extAdminConfig['override.'][$pre];
-                       }
-
-                       $retVal = $val ? $GLOBALS['BE_USER']->uc['TSFE_adminConfig'][$pre . '_' . $val] : 1;
-
-                       if ($pre=='preview' && $this->ext_forcePreview) {
-                               if (!$val) {
-                                       return true;
-                               } else {
-                                       return $retVal;
-                               }
-                       }
-                               // regular check:
-                       if ($this->isAdminModuleOpen($pre)) {   // See if the menu is expanded!
-                               return $retVal;
-                       }
-
-                               // Hook for post processing the frontend admin configuration. Added with TYPO3 4.2, so naming is now incorrect but preserves compatibility.
-                               // @deprecated  since TYPO3 4.3
-                       if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['extEditAction-postProc'])) {
-                               $_params = array('cmd' => &$cmd, 'tce' => &$this->tce, 'pObj' => &$this);
-                               foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['extEditAction-postProc'] as $_funcRef) {
-                                       t3lib_div::callUserFunction($_funcRef, $_params, $this);
-                               }
-                       }
-               }
-       }
-
-       /**
-        * Returns the comma-separated list of page UIDs to be published.
-        *
-        * @return      string
-        */
-       public function getExtPublishList() {
-               return $this->extPublishList;
-       }
-
-       /**
-        * Returns true if admin panel module is open
-        *
-        * @param       string          Module key
-        * @return      boolean         True, if the admin panel is open for the specified admin panel module key.
-        */
-       public function isAdminModuleOpen($pre) {
-               return $GLOBALS['BE_USER']->uc['TSFE_adminConfig']['display_top'] && $GLOBALS['BE_USER']->uc['TSFE_adminConfig']['display_' . $pre];
-       }
-
        /*****************************************************
         *
         * Frontend Editing
@@ -405,13 +183,13 @@ class t3lib_frontendedit {
                                unset($this->TSFE_EDIT['cmd']);
                        } else {
                                $cmd = (string) $this->TSFE_EDIT['cmd'];
-                               if (($cmd != 'edit' || (is_array($this->TSFE_EDIT['data']) && ($this->TSFE_EDIT['update'] || $this->TSFE_EDIT['update_close']))) && $cmd != 'new') {
-                                               // $cmd can be a command like "hide" or "move". If $cmd is "edit" or "new" it's an indication to show the formfields. But if data is sent with update-flag then $cmd = edit is accepted because edit may be sendt because of .keepGoing flag.
-                                       return true;
+                               if (($cmd != 'edit' || (is_array($this->TSFE_EDIT['data']) && ($this->TSFE_EDIT['doSave'] || $this->TSFE_EDIT['update'] || $this->TSFE_EDIT['update_close']))) && $cmd != 'new') {
+                                               // $cmd can be a command like "hide" or "move". If $cmd is "edit" or "new" it's an indication to show the formfields. But if data is sent with update-flag then $cmd = edit is accepted because edit may be sent because of .keepGoing flag.
+                                       return TRUE;
                                }
                        }
                }
-               return false;
+               return FALSE;
        }
 
        /**
@@ -425,7 +203,7 @@ class t3lib_frontendedit {
                if (is_array($this->TSFE_EDIT)) {
                        $cmd = (string) $this->TSFE_EDIT['cmd'];
                        if ($cmd == 'edit' || $cmd == 'new') {
-                               return true;
+                               return TRUE;
                        }
                }
        }
@@ -441,9 +219,15 @@ class t3lib_frontendedit {
        public function editAction() {
                        // Commands:
                list($table, $uid) = explode(':', $this->TSFE_EDIT['record']);
+               $uid = intval($uid);
                $cmd = $this->TSFE_EDIT['cmd'];
 
-               if ($cmd && $table && $uid && isset($GLOBALS['TCA'][$table])) {
+                       // Look for some TSFE_EDIT data that indicates we should save.
+               if (($this->TSFE_EDIT['doSave'] || $this->TSFE_EDIT['update'] || $this->TSFE_EDIT['update_close']) && is_array($this->TSFE_EDIT['data'])) {
+                       $cmd = 'save';
+               }
+
+               if (($cmd == 'save') || ($cmd && $table && $uid && isset($GLOBALS['TCA'][$table]))) {
                                // Hook for defining custom editing actions. Naming is incorrect, but preserves compatibility.
                        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['extEditAction'])) {
                                $_params = array();
@@ -451,9 +235,11 @@ class t3lib_frontendedit {
                                        t3lib_div::callUserFunction($_funcRef, $_params, $this);
                                }
                        }
+
                                // Perform the requested editing command.
-                       if(is_callable(array($this, $cmd))) {
-                               $this->$cmd($table, $uid);
+                       $cmdAction = 'do' . ucwords($cmd);
+                       if (is_callable(array($this, $cmdAction))) {
+                               $this->$cmdAction($table, $uid);
                        } else {
                                throw new UnexpectedValueException(
                                        'The specified frontend edit command (' . $cmd . ') is not valid.',
@@ -461,14 +247,6 @@ class t3lib_frontendedit {
                                );
                        }
                }
-                       // Data:
-               if (($this->TSFE_EDIT['doSave'] || $this->TSFE_EDIT['update'] || $this->TSFE_EDIT['update_close']) && is_array($this->TSFE_EDIT['data'])) {
-                       $this->save($this->TSFE_EDIT['data']);
-                       // pass this on if needed
-                       if ($newuid = $this->tce->substNEWwithIDs['NEW']) {
-                               $this->TSFE_EDIT['newUID'] = $newuid;
-                       }
-               }
        }
 
        /**
@@ -478,11 +256,13 @@ class t3lib_frontendedit {
         * @param       integer         The UID for the record to hide.
         * @return      void
         */
-       public function hide($table, $uid) {
+       public function doHide($table, $uid) {
                $hideField = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'];
                if ($hideField) {
                        $recData = array();
                        $recData[$table][$uid][$hideField] = 1;
+
+                       $this->initializeTceMain();
                        $this->tce->start($recData, array());
                        $this->tce->process_datamap();
                }
@@ -495,11 +275,13 @@ class t3lib_frontendedit {
         * @param       integer         The UID for the record to unhide.
         * @return      void
         */
-       public function unhide($table, $uid) {
+       public function doUnhide($table, $uid) {
                $hideField = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'];
                if ($hideField) {
                        $recData = array();
                        $recData[$table][$uid][$hideField] = 0;
+
+                       $this->initializeTceMain();
                        $this->tce->start($recData, array());
                        $this->tce->process_datamap();
                }
@@ -512,7 +294,7 @@ class t3lib_frontendedit {
         * @param       integer         The UID for the record to hide.
         * @return      void
         */
-       public function up($table, $uid) {
+       public function doUp($table, $uid) {
                $this->move($table, $uid, 'up');
        }
 
@@ -523,71 +305,90 @@ class t3lib_frontendedit {
         * @param       integer         The UID for the record to move.
         * @return      void
         */
-       public function down($table, $uid) {
+       public function doDown($table, $uid) {
                $this->move($table, $uid, 'down');
        }
 
        /**
-        * Moves a record in the specified direction.
+        * Moves a record after a given element. Used for drag.
+        *
+        * @param       string          The table name for the record to move.
+        * @param       integer         The UID for the record to move.
+        * @return      void
+        */
+       public function doMoveAfter($table, $uid) {
+               $afterUID = $GLOBALS['BE_USER']->frontendEdit->TSFE_EDIT['moveAfter'];
+               $this->move($table, $uid, '', $afterUID);
+       }
+
+       /**
+        * Moves a record
         *
         * @param       string          The table name for the record to move.
         * @param       integer         The UID for the record to move.
         * @param       string          The direction to move, either 'up' or 'down'.
+        * @param       integer         The UID of record to move after. This is specified for dragging only.
         * @return      void
         */
-       protected function move($table, $uid, $direction) {
+       protected function move($table, $uid, $direction = '', $afterUID = 0) {
                $cmdData = array();
-               if ($direction == 'up') {
-                       $operator = '<';
-                       $order = 'DESC';
-               } else {
-                       $operator = '>';
-                       $order = 'ASC';
-               }
-
                $sortField = $GLOBALS['TCA'][$table]['ctrl']['sortby'];
                if ($sortField) {
                                // Get self:
-                       $fields = array_unique(t3lib_div::trimExplode(',', $GLOBALS['TCA'][$table]['ctrl']['copyAfterDuplFields'] . ',uid,pid,' . $sortField, true));
+                       $fields = array_unique(t3lib_div::trimExplode(',', $GLOBALS['TCA'][$table]['ctrl']['copyAfterDuplFields'] . ',uid,pid,' . $sortField, TRUE));
                        $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(implode(',', $fields), $table, 'uid=' . $uid);
                        if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
                                        // record before or after
-                               $preview = $this->extGetFeAdminValue('preview');
-                               $copyAfterFieldsQuery = '';
-                               if ($preview) {
-                                       $ignore = array('starttime'=>1, 'endtime'=>1, 'disabled'=>1, 'fe_group'=>1);
+                               if (($GLOBALS['BE_USER']->adminPanel instanceOf tslib_AdminPanel) && ($GLOBALS['BE_USER']->adminPanel->extGetFeAdminValue('preview'))) {
+                                       $ignore = array('starttime' => 1, 'endtime' => 1, 'disabled' => 1, 'fe_group' => 1);
                                }
+                               $copyAfterFieldsQuery = '';
                                if ($GLOBALS['TCA'][$table]['ctrl']['copyAfterDuplFields']) {
-                                       $cAFields = t3lib_div::trimExplode(',', $GLOBALS['TCA'][$table]['ctrl']['copyAfterDuplFields'], false);
-                                       foreach($cAFields as $fieldName) {
+                                       $cAFields = t3lib_div::trimExplode(',', $GLOBALS['TCA'][$table]['ctrl']['copyAfterDuplFields'], TRUE);
+                                       foreach ($cAFields as $fieldName) {
                                                $copyAfterFieldsQuery .= ' AND ' . $fieldName . '="' . $row[$fieldName] . '"';
                                        }
                                }
-
+                               if (!empty($direction)) {
+                                       if ($direction == 'up') {
+                                               $operator = '<';
+                                               $order = 'DESC';
+                                       } else {
+                                               $operator = '>';
+                                               $order = 'ASC';
+                                       }
+                                       $sortCheck = ' AND ' . $sortField . $operator . intval($row[$sortField]);
+                               }
                                $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
-                                                       'uid,pid',
-                                                       $table,
-                                                       'pid=' . intval($row['pid']) .
-                                                               ' AND ' . $sortField . $operator . intval($row[$sortField]) .
+                                       'uid,pid',
+                                       $table,
+                                               'pid=' . intval($row['pid']) .
+                                                               $sortCheck .
                                                                $copyAfterFieldsQuery .
                                                                $GLOBALS['TSFE']->sys_page->enableFields($table, '', $ignore),
-                                                       '',
-                                                       $sortField . ' ' . $order,
-                                                       '2'
-                                               );
+                                       '',
+                                               $sortField . ' ' . $order,
+                                       '2'
+                               );
                                if ($row2 = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-                                       if ($direction == 'down') {
+                                       if ($afterUID) {
+                                               $cmdData[$table][$uid]['move'] = -$afterUID;
+                                       }
+                                       elseif ($direction == 'down') {
                                                $cmdData[$table][$uid]['move'] = -$row2['uid'];
-                                       } elseif ($row3 = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {        // Must take the second record above...
+                                       }
+                                       elseif ($row3 = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { // Must take the second record above...
                                                $cmdData[$table][$uid]['move'] = -$row3['uid'];
-                                       } else {        // ... and if that does not exist, use pid
+                                       }
+                                       else { // ... and if that does not exist, use pid
                                                $cmdData[$table][$uid]['move'] = $row['pid'];
                                        }
                                } elseif ($direction == 'up') {
                                        $cmdData[$table][$uid]['move'] = $row['pid'];
                                }
                        }
-                       if (count($cmdData)) {
+                       if (!empty($cmdData)) {
+                               $this->initializeTceMain();
                                $this->tce->start(array(), $cmdData);
                                $this->tce->process_cmdmap();
                        }
@@ -601,9 +402,10 @@ class t3lib_frontendedit {
         * @param       integer         The UID for the record to delete.
         * @return      void
         */
-       public function delete($table, $uid) {
+       public function doDelete($table, $uid) {
                $cmdData[$table][$uid]['delete'] = 1;
                if (count($cmdData)) {
+                       $this->initializeTceMain();
                        $this->tce->start(array(), $cmdData);
                        $this->tce->process_cmdmap();
                }
@@ -612,13 +414,55 @@ class t3lib_frontendedit {
        /**
         * Saves a record based on its data array.
         *
-        * @param       array           Array of record data to be saved.
+        * @param       string          The table name for the record to save.
+        * @param       integer         The UID for the record to save.
         * @return      void
         */
-       public function save(array $data) {
-               $this->tce->start($data, array());
-               $this->tce->process_uploads($_FILES);
-               $this->tce->process_datamap();
+       public function doSave($table, $uid) {
+               $data = $this->TSFE_EDIT['data'];
+
+               if (!empty($data)) {
+                       $this->initializeTceMain();
+                       $this->tce->start($data, array());
+                       $this->tce->process_uploads($_FILES);
+                       $this->tce->process_datamap();
+
+                               // Save the new UID back into TSFE_EDIT
+                       $newUID = $this->tce->substNEWwithIDs['NEW'];
+                       if ($newUID) {
+                               $GLOBALS['BE_USER']->frontendEdit->TSFE_EDIT['newUID'] = $newUID;
+                       }
+               }
+       }
+
+       /**
+        * Saves a record based on its data array and closes it.
+        *
+        * @param       string          The table name for the record to save.
+        * @param       integer         The UID for the record to save.
+        * @return      void
+        * @note        This method is only a wrapper for doSave() but is needed so
+        *                      that frontend editing views can handle "save" differently from
+        *                      "save and close".
+        *                      Example: When editing a page record, "save" reloads the same
+        *                      editing form.  "Save and close" reloads the entire page at
+        *                      the appropriate URL.
+        */
+       public function doSaveAndClose($table, $uid) {
+               $this->doSave($table, $uid);
+       }
+
+
+       /**
+        * Stub for closing a record. No real functionality needed since content
+        * element rendering will take care of everything.
+        *
+        * @param       string          The table name for the record to close.
+        * @param       integer         The UID for the record to close.
+        * @return      void
+        */
+       public function doClose($table, $uid) {
+               // Do nothing.
        }
 
        /**
@@ -642,9 +486,9 @@ class t3lib_frontendedit {
                }
 
                if ($GLOBALS['BE_USER']->checkLanguageAccess($lang)) {
-                       $languageAccess = true;
+                       $languageAccess = TRUE;
                } else {
-                       $languageAccess = false;
+                       $languageAccess = FALSE;
                }
 
                return $languageAccess;
@@ -656,40 +500,50 @@ class t3lib_frontendedit {
         * @param       string  The name of the table.
         * @param       array   The data array.
         * @param       array   The configuration array for the edit panel.
+        * @param       boolean Boolean indicating whether recordEditAccessInternals should not be checked. Defaults
+        *                                       to true but doesn't makes sense when creating new records on a page.
         * @return      boolean
         */
-       protected function allowedToEdit($table, array $dataArray, array $conf) {
+       protected function allowedToEdit($table, array $dataArray, array $conf, $checkEditAccessInternals = TRUE) {
 
                        // Unless permissions specifically allow it, editing is not allowed.
-               $mayEdit = false;
+               $mayEdit = FALSE;
 
-               if ($table=='pages') {
-                               // 2 = permission to edit the page
-                       if($GLOBALS['BE_USER']->isAdmin() || $GLOBALS['BE_USER']->doesUserHaveAccess($dataArray, 2)) {
-                               $mayEdit = true;
-                       }
+               if ($checkEditAccessInternals) {
+                       $editAccessInternals = $GLOBALS['BE_USER']->recordEditAccessInternals($table, $dataArray, FALSE, FALSE);
                } else {
-                               // 16 = permission to edit content on the page
-                       if ($GLOBALS['BE_USER']->isAdmin() || $GLOBALS['BE_USER']->doesUserHaveAccess(t3lib_BEfunc::getRecord('pages', $dataArray['pid']), 16)) {
-                               $mayEdit = true;
-                       }
+                       $editAccessInternals = TRUE;
                }
 
-               if (!$conf['onlyCurrentPid'] || ($dataArray['pid'] == $GLOBALS['TSFE']->id)) {
-                               // Permissions:
-                       $types = t3lib_div::trimExplode(',', t3lib_div::strtolower($conf['allow']),1);
-                       $allow = array_flip($types);
-
-                       $perms = $GLOBALS['BE_USER']->calcPerms($GLOBALS['TSFE']->page);
+               if ($editAccessInternals) {
                        if ($table == 'pages') {
-                               $allow = $this->getAllowedEditActions($table, $conf, $dataArray['pid'], $allow);
-
-                                       // Can only display editbox if there are options in the menu
-                               if (count($allow)) {
-                                       $mayEdit = true;
+                                       // 2 = permission to edit the page
+                               if ($GLOBALS['BE_USER']->isAdmin() || $GLOBALS['BE_USER']->doesUserHaveAccess($dataArray, 2)) {
+                                       $mayEdit = TRUE;
                                }
                        } else {
-                               $mayEdit = count($allow) && ($perms & 16);
+                                       // 16 = permission to edit content on the page
+                               if ($GLOBALS['BE_USER']->isAdmin() || $GLOBALS['BE_USER']->doesUserHaveAccess(t3lib_BEfunc::getRecord('pages', $dataArray['pid']), 16)) {
+                                       $mayEdit = TRUE;
+                               }
+                       }
+
+                       if (!$conf['onlyCurrentPid'] || ($dataArray['pid'] == $GLOBALS['TSFE']->id)) {
+                                       // Permissions:
+                               $types = t3lib_div::trimExplode(',', t3lib_div::strtolower($conf['allow']), 1);
+                               $allow = array_flip($types);
+
+                               $perms = $GLOBALS['BE_USER']->calcPerms($GLOBALS['TSFE']->page);
+                               if ($table == 'pages') {
+                                       $allow = $this->getAllowedEditActions($table, $conf, $dataArray['pid'], $allow);
+
+                                               // Can only display editbox if there are options in the menu
+                                       if (count($allow)) {
+                                               $mayEdit = TRUE;
+                                       }
+                               } else {
+                                       $mayEdit = count($allow) && ($perms & 16);
+                               }
                        }
                }
 
@@ -708,24 +562,24 @@ class t3lib_frontendedit {
        protected function getAllowedEditActions($table, array $conf, $pid, $allow = '') {
 
                if (!$allow) {
-                       $types = t3lib_div::trimExplode(',', t3lib_div::strtolower($conf['allow']), true);
+                       $types = t3lib_div::trimExplode(',', t3lib_div::strtolower($conf['allow']), TRUE);
                        $allow = array_flip($types);
                }
 
                if (!$conf['onlyCurrentPid'] || $pid == $GLOBALS['TSFE']->id) {
                                // Permissions:
-                       $types = t3lib_div::trimExplode(',', t3lib_div::strtolower($conf['allow']), true);
+                       $types = t3lib_div::trimExplode(',', t3lib_div::strtolower($conf['allow']), TRUE);
                        $allow = array_flip($types);
 
                        $perms = $GLOBALS['BE_USER']->calcPerms($GLOBALS['TSFE']->page);
-                       if ($table=='pages') {
+                       if ($table == 'pages') {
                                        // rootpage!
                                if (count($GLOBALS['TSFE']->config['rootLine']) == 1) {
                                        unset($allow['move']);
                                        unset($allow['hide']);
                                        unset($allow['delete']);
                                }
-                               if (!($perms & 2)){
+                               if (!($perms & 2)) {
                                        unset($allow['edit']);
                                        unset($allow['move']);
                                        unset($allow['hide']);
@@ -733,7 +587,7 @@ class t3lib_frontendedit {
                                if (!($perms & 4)) {
                                        unset($allow['delete']);
                                }
-                               if (!($perms&8)) {
+                               if (!($perms & 8)) {
                                        unset($allow['new']);
                                }
                        }
@@ -741,10 +595,45 @@ class t3lib_frontendedit {
 
                return $allow;
        }
+
+       /**
+        * Adds any extra Javascript includes needed for Front-end editing
+        *
+        * @param       none
+        * @return      string
+        */
+       public function getJavascriptIncludes() {
+                       // No extra JS includes needed
+               return '';
+       }
+
+       /**
+        * Gets the hidden fields (array key=field name, value=field value) to be used in the edit panel for a particular content element.
+        * In the normal case, no hidden fields are needed but special controllers such as TemplaVoila need to track flexform pointers, etc.
+        *
+        * @param       array   The data array for a specific content element.
+        * @return      array
+        */
+       public function getHiddenFields(array $dataArray) {
+                       // No special hidden fields needed.
+               return array();
+       }
+
+       /**
+        * Initializes t3lib_TCEmain since it is used on modification actions.
+        *
+        * @return      void
+        */
+       protected function initializeTceMain() {
+               if (!isset($this->tce)) {
+                       $this->tce = t3lib_div::makeInstance('t3lib_TCEmain');
+                       $this->tce->stripslashes_values = 0;
+               }
+       }
 }
 
-if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_frontendedit.php']) {
-       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_frontendedit.php']);
+if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_frontendedit.php'])) {
+       include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_frontendedit.php']);
 }
 
 ?>
\ No newline at end of file