+2010-01-25 Steffen Kamper <info@sk-typo3.de>
+
+ * Added feature #13313: ExtDirect API (thanks to Stefan Galinski and the T3UXW09 team)
+
2010-01-24 Steffen Kamper <info@sk-typo3.de>
* Fixed bug #13090: 4.4.0 trunk: version warning with CSS styled content
/**
* 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;
+ }
}
}
'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!
--- /dev/null
+<?php\r
+/***************************************************************\r
+* Copyright notice\r
+*\r
+* (c) 2010 Sebastian Kurfuerst <sebastian@typo3.org>\r
+* All rights reserved\r
+*\r
+* This script is part of the TYPO3 project. The TYPO3 project is\r
+* free software; you can redistribute it and/or modify\r
+* it under the terms of the GNU General Public License as published by\r
+* the Free Software Foundation; either version 2 of the License, or\r
+* (at your option) any later version.\r
+*\r
+* The GNU General Public License can be found at\r
+* http://www.gnu.org/copyleft/gpl.html.\r
+* A copy is found in the textfile GPL.txt and important notices to the license\r
+* from the author is found in LICENSE.txt distributed with these scripts.\r
+*\r
+*\r
+* This script is distributed in the hope that it will be useful,\r
+* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+* GNU General Public License for more details.\r
+*\r
+* This copyright notice MUST APPEAR in all copies of the script!\r
+***************************************************************/\r
+\r
+/**\r
+ * Ext Direct API Generator\r
+ *\r
+ * @author Sebastian Kurfuerst <sebastian@typo3.org>\r
+ * @author Stefan Galinski <stefan.galinski@gmail.com>\r
+ * @package TYPO3\r
+ */\r
+class t3lib_ExtJs_ExtDirectAPI {\r
+ /**\r
+ * Parses the ExtDirect configuration array "$GLOBALS['TYPO3_CONF_VARS']['BE']['ExtDirect']"\r
+ * and feeds the given typo3ajax instance with the resulting informations. The get parameter\r
+ * "namespace" will be used to filter the configuration.\r
+ *\r
+ * This method makes usage of the reflection mechanism to fetch the methods inside the\r
+ * defined classes together with their amount of parameters. This informations are building\r
+ * the API and are required by ExtDirect.\r
+ *\r
+ * @param array $ajaxParams ajax parameters\r
+ * @param TYPO3AJAX $ajaxObj typo3ajax instance\r
+ * @return void\r
+ */\r
+ public function getAPI($ajaxParams, TYPO3AJAX $ajaxObj) {\r
+ $filterNamespace = t3lib_div::_GET('namespace');\r
+\r
+ $javascriptNamespaces = array();\r
+ if (is_array($GLOBALS['TYPO3_CONF_VARS']['BE']['ExtDirect'])) {\r
+ foreach ($GLOBALS['TYPO3_CONF_VARS']['BE']['ExtDirect'] as $javascriptName => $className) {\r
+ $splittedJavascriptName = explode('.', $javascriptName);\r
+ $javascriptObjectName = array_pop($splittedJavascriptName);\r
+ $javascriptNamespace = implode('.', $splittedJavascriptName);\r
+\r
+ // only items inside the wanted namespace\r
+ if (strpos($javascriptNamespace, $filterNamespace) !== 0) {\r
+ continue;\r
+ }\r
+\r
+ if (!isset($javascriptNamespaces[$javascriptNamespace])) {\r
+ $javascriptNamespaces[$javascriptNamespace] = array(\r
+ 'url' => 'ajax.php?ajaxID=ExtDirect::route&namespace=' . rawurlencode($javascriptNamespace),\r
+ 'type' => 'remoting',\r
+ 'actions' => array(),\r
+ 'namespace' => $javascriptNamespace\r
+ );\r
+ }\r
+\r
+ $serverObject = t3lib_div::getUserObj($className, FALSE);\r
+ $javascriptNamespaces[$javascriptNamespace]['actions'][$javascriptObjectName] = array();\r
+ foreach (get_class_methods($serverObject) as $methodName) {\r
+ $reflectionMethod = new ReflectionMethod($serverObject, $methodName);\r
+ $numberOfParameters = $reflectionMethod->getNumberOfParameters();\r
+\r
+ $javascriptNamespaces[$javascriptNamespace]['actions'][$javascriptObjectName][] = array(\r
+ 'name' => $methodName,\r
+ 'len' => $numberOfParameters\r
+ ); \r
+ }\r
+ }\r
+ }\r
+\r
+ if (count($javascriptNamespaces)) {\r
+ $setup = '\r
+ if (typeof Ext.app.ExtDirectAPI != "object") {\r
+ Ext.app.ExtDirectAPI = {};\r
+ }\r
+ ';\r
+\r
+ $ajaxObj->setContent($javascriptNamespaces);\r
+ $ajaxObj->setContentFormat('javascript');\r
+ $ajaxObj->setJavascriptCallbackWrap($setup . 'Ext.app.ExtDirectAPI = Object.extend(Ext.app.ExtDirectAPI, |);');\r
+ }\r
+ }\r
+}\r
+\r
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_extjs_extdirectapi.php']) {\r
+ include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_extjs_extdirectapi.php']);\r
+}\r
+\r
+?>\r
--- /dev/null
+<?php\r
+/***************************************************************\r
+* Copyright notice\r
+*\r
+* (c) 2010 Sebastian Kurfuerst <sebastian@typo3.org>\r
+* All rights reserved\r
+*\r
+* This script is part of the TYPO3 project. The TYPO3 project is\r
+* free software; you can redistribute it and/or modify\r
+* it under the terms of the GNU General Public License as published by\r
+* the Free Software Foundation; either version 2 of the License, or\r
+* (at your option) any later version.\r
+*\r
+* The GNU General Public License can be found at\r
+* http://www.gnu.org/copyleft/gpl.html.\r
+* A copy is found in the textfile GPL.txt and important notices to the license\r
+* from the author is found in LICENSE.txt distributed with these scripts.\r
+*\r
+*\r
+* This script is distributed in the hope that it will be useful,\r
+* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+* GNU General Public License for more details.\r
+*\r
+* This copyright notice MUST APPEAR in all copies of the script!\r
+***************************************************************/\r
+\r
+/**\r
+ * Ext Direct Router\r
+ *\r
+ * @author Sebastian Kurfuerst <sebastian@typo3.org>\r
+ * @author Stefan Galinski <stefan.galinski@gmail.com>\r
+ * @package TYPO3\r
+ */\r
+class t3lib_ExtJs_ExtDirectRouter {\r
+ /**\r
+ * Dispatches the incoming calls to methods about the ExtDirect API.\r
+ *\r
+ * @param aray $ajaxParams ajax parameters\r
+ * @param TYPO3AJAX $ajaxObj typo3ajax instance\r
+ * @return void\r
+ */\r
+ public function route($ajaxParams, TYPO3AJAX $ajaxObj) {\r
+ try {\r
+ $isForm = false;\r
+ $isUpload = false;\r
+ $rawPostData = file_get_contents('php://input');\r
+ $namespace = t3lib_div::_GET('namespace');\r
+\r
+ if (!empty($rawPostData)) {\r
+ $ajaxObj->setContentFormat('jsonbody');\r
+ $request = json_decode($rawPostData);\r
+ } else {\r
+ throw new t3lib_error_Exception('ExtDirect: Missing Parameters!');\r
+ }\r
+\r
+ $response = null;\r
+ if (is_array($request)) {\r
+ $response = array();\r
+ foreach ($request as $singleRequest) {\r
+ $response[] = $this->processRpc($singleRequest, $namespace);\r
+ }\r
+ } else {\r
+ $response = $this->processRpc($request, $namespace);\r
+ }\r
+\r
+ } catch (t3lib_error_Exception $exception) {\r
+ $response = array(\r
+ 'type' => 'exception',\r
+ 'message' => $exception->getMessage(),\r
+ 'where' => $exception->getTraceAsString()\r
+ );\r
+ }\r
+\r
+ $ajaxObj->setContent($response);\r
+ }\r
+\r
+\r
+ /**\r
+ * Processes an incoming extDirect call by executing the defined method. The configuration\r
+ * array "$GLOBALS['TYPO3_CONF_VARS']['BE']['ExtDirect']" is taken to find the class/method\r
+ * information.\r
+ *\r
+ * @param object $singleRequest request object from extJS\r
+ * @param string $namespace namespace like TYPO3.Backend\r
+ * @return mixed return value of the called method\r
+ */\r
+ protected function processRpc($singleRequest, $namespace) {\r
+ try {\r
+ $endpointName = $namespace . '.' . $singleRequest->action;\r
+ \r
+ // theoretically this can never happen, because of an javascript error on\r
+ // the client side due the missing namespace/endpoint\r
+ if (!isset($GLOBALS['TYPO3_CONF_VARS']['BE']['ExtDirect'][$endpointName])) {\r
+ throw new t3lib_error_Exception('ExtDirect: Call to undefined endpoint: ' . $endpointName);\r
+ }\r
+\r
+ $response = array(\r
+ 'type' => 'rpc',\r
+ 'tid' => $singleRequest->tid,\r
+ 'action' => $singleRequest->action,\r
+ 'method' => $singleRequest->method\r
+ );\r
+\r
+ $endpointObject = t3lib_div::getUserObj(\r
+ $GLOBALS['TYPO3_CONF_VARS']['BE']['ExtDirect'][$endpointName],\r
+ FALSE\r
+ );\r
+ \r
+ $response['result'] = call_user_func_array(\r
+ array($endpointObject, $singleRequest->method),\r
+ is_array($singleRequest->data) ? $singleRequest->data : array()\r
+ );\r
+\r
+ } catch (t3lib_error_Exception $exception) {\r
+ $response = array(\r
+ 'type' => 'exception',\r
+ 'message' => $exception->getMessage(),\r
+ 'where' => $exception->getTraceAsString()\r
+ );\r
+ }\r
+\r
+ return $response;\r
+ }\r
+}\r
+\r
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_extjs_extdirectrouter.php']) {\r
+ include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_extjs_extdirectrouter.php']);\r
+}\r
+\r
+?>\r
'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 = '';
$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);
protected $contentFormat = 'plain';
protected $charset = 'utf-8';
protected $requestCharset = 'utf-8';
+ protected $javascriptCallbackWrap = '
+ <script type="text/javascript">
+ /*<![CDATA[*/
+ response = |;
+ /*]]>*/
+ </script>
+ ';
/**
* sets the charset and the ID for the AJAX call
/**
* 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) {
}
}
+ /**
+ * Specifies the wrap to be used if contentFormat is "javascript".
+ * The wrap used by default stores the results in a variable "response" and
+ * adds <script>-Tags around it.
+ *
+ * @param string $javascriptCallbackWrap the javascript callback wrap to be used
+ * @return void
+ */
+ public function setJavascriptCallbackWrap($javascriptCallbackWrap) {
+ $this->javascriptCallbackWrap = $javascriptCallbackWrap;
+ }
/**
* sets an error message and the error flag
$GLOBALS['LANG']->csConvObj->convArray($this->content, $this->charset, $this->requestCharset);
}
- $content = '<script type="text/javascript">
- /*<![CDATA[*/
-
- response = ' . json_encode($this->content) . ';
-
- /*]]>*/
- </script>';
+ $content = str_replace('|', json_encode($this->content), $this->javascriptCallbackWrap);
header('Content-type: text/html; charset=' . $this->requestCharset);
echo $content;