Index: t3lib/config_default.php =================================================================== --- t3lib/config_default.php (revision 6817) +++ t3lib/config_default.php (working copy) @@ -279,8 +279,11 @@ 'BackendLogin::isTimedOut' => 'typo3/classes/class.ajaxlogin.php:AjaxLogin->isTimedOut', 'BackendLogin::getChallenge' => 'typo3/classes/class.ajaxlogin.php:AjaxLogin->getChallenge', 'WorkspaceMenu::toggleWorkspacePreview' => 'typo3/classes/class.workspaceselector.php:WorkspaceSelector->toggleWorkspacePreview', - 'WorkspaceMenu::setWorkspace' => 'typo3/classes/class.workspaceselector.php:WorkspaceSelector->setWorkspace' + 'WorkspaceMenu::setWorkspace' => 'typo3/classes/class.workspaceselector.php:WorkspaceSelector->setWorkspace', + 'ExtDirect::getAPI' => 't3lib/extjs/class.t3lib_extjs_extdirectapi.php:t3lib_ExtJs_ExtDirectAPI->getAPI', + 'ExtDirect::route' => 't3lib/extjs/class.t3lib_extjs_extdirectrouter.php:t3lib_ExtJs_ExtDirectRouter->route', ), + 'ExtDirect' => array(), // array of key value pairs (provider -> location:className) that holds the classes for the ExtDirect functionality 'XCLASS' => array(), // See 'Inside TYPO3' document for more information. ), 'FE' => array( // Configuration for the TypoScript frontend (FE). Nothing here relates to the administration backend! Index: t3lib/class.t3lib_pagerenderer.php =================================================================== --- t3lib/class.t3lib_pagerenderer.php (revision 6817) +++ t3lib/class.t3lib_pagerenderer.php (working copy) @@ -687,12 +687,17 @@ /** * Adds Ext.onready code, which will be wrapped in Ext.onReady(function() {...}); * - * @param string $block + * @param string $block javascript code + * @param boolean $forceOnTop position of the javascript code (TRUE for putting it on top, default is FALSE = bottom) * @return void */ - public function addExtOnReadyCode($block) { + public function addExtOnReadyCode($block, $forceOnTop = FALSE) { if (!in_array($block, $this->extOnReadyCode)) { - $this->extOnReadyCode[] = $block; + if ($forceOnTop) { + array_unshift($this->extOnReadyCode, $block); + } else { + $this->extOnReadyCode[] = $block; + } } } Index: t3lib/extjs/class.t3lib_extjs_extdirectrouter.php =================================================================== --- t3lib/extjs/class.t3lib_extjs_extdirectrouter.php (revision 0) +++ t3lib/extjs/class.t3lib_extjs_extdirectrouter.php (revision 0) @@ -0,0 +1,131 @@ + +* 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! +***************************************************************/ + +/** + * Ext Direct Router + * + * @author Sebastian Kurfuerst + * @author Stefan Galinski + * @package TYPO3 + */ +class t3lib_ExtJs_ExtDirectRouter { + /** + * Dispatches the incoming calls to methods about the ExtDirect API. + * + * @param aray $ajaxParams ajax parameters + * @param TYPO3AJAX $ajaxObj typo3ajax instance + * @return void + */ + public function route($ajaxParams, TYPO3AJAX $ajaxObj) { + try { + $isForm = false; + $isUpload = false; + $rawPostData = file_get_contents('php://input'); + $namespace = t3lib_div::_GET('namespace'); + + if (!empty($rawPostData)) { + $ajaxObj->setContentFormat('jsonbody'); + $request = json_decode($rawPostData); + } else { + throw new t3lib_error_Exception('ExtDirect: Missing Parameters!'); + } + + $response = null; + if (is_array($request)) { + $response = array(); + foreach ($request as $singleRequest) { + $response[] = $this->processRpc($singleRequest, $namespace); + } + } else { + $response = $this->processRpc($request, $namespace); + } + + } catch (t3lib_error_Exception $exception) { + $response = array( + 'type' => 'exception', + 'message' => $exception->getMessage(), + 'where' => $exception->getTraceAsString() + ); + } + + $ajaxObj->setContent($response); + } + + + /** + * Processes an incoming extDirect call by executing the defined method. The configuration + * array "$GLOBALS['TYPO3_CONF_VARS']['BE']['ExtDirect']" is taken to find the class/method + * information. + * + * @param object $singleRequest request object from extJS + * @param string $namespace namespace like TYPO3.Backend + * @return mixed return value of the called method + */ + protected function processRpc($singleRequest, $namespace) { + try { + $endpointName = $namespace . '.' . $singleRequest->action; + + // theoretically this can never happen, because of an javascript error on + // the client side due the missing namespace/endpoint + if (!isset($GLOBALS['TYPO3_CONF_VARS']['BE']['ExtDirect'][$endpointName])) { + throw new t3lib_error_Exception('ExtDirect: Call to undefined endpoint: ' . $endpointName); + } + + $response = array( + 'type' => 'rpc', + 'tid' => $singleRequest->tid, + 'action' => $singleRequest->action, + 'method' => $singleRequest->method + ); + + $endpointObject = t3lib_div::getUserObj( + $GLOBALS['TYPO3_CONF_VARS']['BE']['ExtDirect'][$endpointName], + FALSE + ); + + $response['result'] = call_user_func_array( + array($endpointObject, $singleRequest->method), + is_array($singleRequest->data) ? $singleRequest->data : array() + ); + + } catch (t3lib_error_Exception $exception) { + $response = array( + 'type' => 'exception', + 'message' => $exception->getMessage(), + 'where' => $exception->getTraceAsString() + ); + } + + return $response; + } +} + +if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_extjs_extdirectrouter.php']) { + include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_extjs_extdirectrouter.php']); +} + +?> Index: t3lib/extjs/class.t3lib_extjs_extdirectapi.php =================================================================== --- t3lib/extjs/class.t3lib_extjs_extdirectapi.php (revision 0) +++ t3lib/extjs/class.t3lib_extjs_extdirectapi.php (revision 0) @@ -0,0 +1,105 @@ + +* 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! +***************************************************************/ + +/** + * Ext Direct API Generator + * + * @author Sebastian Kurfuerst + * @author Stefan Galinski + * @package TYPO3 + */ +class t3lib_ExtJs_ExtDirectAPI { + /** + * Parses the ExtDirect configuration array "$GLOBALS['TYPO3_CONF_VARS']['BE']['ExtDirect']" + * and feeds the given typo3ajax instance with the resulting informations. The get parameter + * "namespace" will be used to filter the configuration. + * + * This method makes usage of the reflection mechanism to fetch the methods inside the + * defined classes together with their amount of parameters. This informations are building + * the API and are required by ExtDirect. + * + * @param array $ajaxParams ajax parameters + * @param TYPO3AJAX $ajaxObj typo3ajax instance + * @return void + */ + public function getAPI($ajaxParams, TYPO3AJAX $ajaxObj) { + $filterNamespace = t3lib_div::_GET('namespace'); + + $javascriptNamespaces = array(); + if (is_array($GLOBALS['TYPO3_CONF_VARS']['BE']['ExtDirect'])) { + foreach ($GLOBALS['TYPO3_CONF_VARS']['BE']['ExtDirect'] as $javascriptName => $className) { + $splittedJavascriptName = explode('.', $javascriptName); + $javascriptObjectName = array_pop($splittedJavascriptName); + $javascriptNamespace = implode('.', $splittedJavascriptName); + + // only items inside the wanted namespace + if (strpos($javascriptNamespace, $filterNamespace) !== 0) { + continue; + } + + if (!isset($javascriptNamespaces[$javascriptNamespace])) { + $javascriptNamespaces[$javascriptNamespace] = array( + 'url' => 'ajax.php?ajaxID=ExtDirect::route&namespace=' . rawurlencode($javascriptNamespace), + 'type' => 'remoting', + 'actions' => array(), + 'namespace' => $javascriptNamespace + ); + } + + $serverObject = t3lib_div::getUserObj($className, FALSE); + $javascriptNamespaces[$javascriptNamespace]['actions'][$javascriptObjectName] = array(); + foreach (get_class_methods($serverObject) as $methodName) { + $reflectionMethod = new ReflectionMethod($serverObject, $methodName); + $numberOfParameters = $reflectionMethod->getNumberOfParameters(); + + $javascriptNamespaces[$javascriptNamespace]['actions'][$javascriptObjectName][] = array( + 'name' => $methodName, + 'len' => $numberOfParameters + ); + } + } + } + + if (count($javascriptNamespaces)) { + $setup = ' + if (typeof Ext.app.ExtDirectAPI != "object") { + Ext.app.ExtDirectAPI = {}; + } + '; + + $ajaxObj->setContent($javascriptNamespaces); + $ajaxObj->setContentFormat('javascript'); + $ajaxObj->setJavascriptCallbackWrap($setup . 'Ext.app.ExtDirectAPI = Object.extend(Ext.app.ExtDirectAPI, |);'); + } + } +} + +if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_extjs_extdirectapi.php']) { + include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_extjs_extdirectapi.php']); +} + +?> Index: typo3/classes/class.typo3ajax.php =================================================================== --- typo3/classes/class.typo3ajax.php (revision 6817) +++ typo3/classes/class.typo3ajax.php (working copy) @@ -41,6 +41,13 @@ protected $contentFormat = 'plain'; protected $charset = 'utf-8'; protected $requestCharset = 'utf-8'; + protected $javascriptCallbackWrap = ' + + '; /** * sets the charset and the ID for the AJAX call @@ -138,7 +145,7 @@ /** * sets the content format for the ajax call * - * @param string can be one of 'plain' (default), 'xml', 'json', 'jsonbody' or 'jsonhead' + * @param string can be one of 'plain' (default), 'xml', 'json', 'javascript', 'jsonbody' or 'jsonhead' * @return void */ public function setContentFormat($format) { @@ -147,6 +154,17 @@ } } + /** + * Specifies the wrap to be used if contentFormat is "javascript". + * The wrap used by default stores the results in a variable "response" and + * adds '; - header('Content-type: text/html; charset=' . $this->requestCharset); echo $content; } Index: typo3/backend.php =================================================================== --- typo3/backend.php (revision 6817) +++ typo3/backend.php (working copy) @@ -102,11 +102,13 @@ 'js/modulemenu.js', 'js/iecompatibility.js', 'js/flashupload.js', - '../t3lib/jsfunc.evalfield.js' + '../t3lib/jsfunc.evalfield.js', + 'ajax.php?ajaxID=ExtDirect::getAPI&namespace=TYPO3.Backend' ); + $this->jsFilesAfterInline = array( 'js/backend.js', - 'js/loginrefresh.js', + 'js/loginrefresh.js', ); // add default BE css $this->css = ''; @@ -210,6 +212,16 @@ $pageRenderer->loadScriptaculous('builder,effects,controls,dragdrop'); $pageRenderer->loadExtJS(); + // register the extDirect API providers + // Note: we need to iterate thru the object, because the addProvider method + // does this only with multiple arguments + $pageRenderer->addExtOnReadyCode( + 'for (var api in Ext.app.ExtDirectAPI) { + Ext.Direct.addProvider(Ext.app.ExtDirectAPI[api]); + }', + TRUE + ); + // remove duplicate entries $this->jsFiles = array_unique($this->jsFiles);