Added feature #11819: Added inline Javascript rendering type for TYPO3AJAX
[Packages/TYPO3.CMS.git] / typo3 / classes / class.typo3ajax.php
index 1e65d60..1414567 100644 (file)
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 2008 Benjamin Mack <mack@xnos.org>
+*  (c) 2008-2009 Benjamin Mack <mack@xnos.org>
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
@@ -24,6 +24,7 @@
 *
 *  This copyright notice MUST APPEAR in all copies of the script!
 ***************************************************************/
+
 /**
  * class to hold all the information about an AJAX call and send
  * the right headers for the request type
  * @subpackage core
  */
 class TYPO3AJAX {
-       private $id = null;
-       private $errorMessage = null;
-       private $isError = false;
-       private $content = array();
-       private $contentFormat = 'plain';       // could be 'plain' (default), 'xml', 'json', 'jsonbody' or 'jsonhead'
-       private $charset = 'utf-8';
+       protected $ajaxId        = null;
+       protected $errorMessage  = null;
+       protected $isError       = false;
+       protected $content       = array();
+       protected $contentFormat = 'plain';
+       protected $charset       = 'utf-8';
+       protected $requestCharset = 'utf-8';
 
        /**
         * sets the charset and the ID for the AJAX call
+        * due some charset limitations in Javascript (prototype uses encodeURIcomponent, which converts
+        * all data to utf-8), we need to detect if the encoding of the request differs from the
+        * backend encoding (e.g. forceCharset), and then convert all incoming data (_GET and _POST)
+        * in the expected backend encoding.
         *
-        * @param       string  the AJAX id
+        * @param       string          the AJAX id
         * @return      void
         */
-       public function init($id) {
-               global $TYPO3_CONF_VARS;
-               
-               if (isset($TYPO3_CONF_VARS['BE']['forceCharset']) && trim($TYPO3_CONF_VARS['BE']['forceCharset'])) {
-                       $this->charset = $TYPO3_CONF_VARS['BE']['forceCharset'];
+       public function __construct($ajaxId) {
+
+               if ($GLOBALS['LANG']->charSet != $this->charset) {
+                       $this->charset = $GLOBALS['LANG']->charSet;
+               }
+
+                       // get charset from current AJAX request (which is expected to be utf-8)
+               preg_match('/;\s*charset\s*=\s*([a-zA-Z0-9_-]*)/i', $_SERVER['CONTENT_TYPE'], $contenttype);
+               $charset = $GLOBALS['LANG']->csConvObj->parse_charset($contenttype[1]);
+               if ($charset && $charset != $this->requestCharset) {
+                       $this->requestCharset = $charset;
+               }
+
+                               // if the AJAX request does not have the same encoding like the backend
+                               // we need to convert the POST and GET parameters in the right charset
+               if ($this->charset != $this->requestCharset) {
+                       $GLOBALS['LANG']->csConvObj->convArray($_POST, $this->requestCharset, $this->charset);
+                       $GLOBALS['LANG']->csConvObj->convArray($_GET,  $this->requestCharset, $this->charset);
                }
 
-               $this->id = $id;
+               $this->ajaxId = $ajaxId;
        }
 
 
        /**
         * returns the ID for the AJAX call
         *
-        * @return      string  the AJAX id
+        * @return      string          the AJAX id
         */
-       public function getID() {
-               return $this->id;
+       public function getAjaxID() {
+               return $this->ajaxId;
        }
 
 
        /**
         * overwrites the existing content with the first parameter
         *
-        * @param       array   the new content
-        * @return      mixed   the old content as array; if the new content was not an array, false is returned
+        * @param       array           the new content
+        * @return      mixed           the old content as array; if the new content was not an array, false is returned
         */
        public function setContent($content) {
                $oldcontent = false;
@@ -86,9 +105,9 @@ class TYPO3AJAX {
        /**
         * adds new content
         *
-        * @param       string  the new content key where the content should be added in the content array
-        * @param       string  the new content to add
-        * @return      mixed   the old content; if the old content didn't exist before, false is returned
+        * @param       string          the new content key where the content should be added in the content array
+        * @param       string          the new content to add
+        * @return      mixed           the old content; if the old content didn't exist before, false is returned
         */
        public function addContent($key, $content) {
                $oldcontent = false;
@@ -109,7 +128,7 @@ class TYPO3AJAX {
        /**
         * returns the content for the ajax call
         *
-        * @return      mixed   the content for a specific key or the whole content
+        * @return      mixed           the content for a specific key or the whole content
         */
        public function getContent($key = '') {
                return ($key && array_key_exists($key, $this->content) ? $this->content[$key] : $this->content);
@@ -118,12 +137,12 @@ class TYPO3AJAX {
 
        /**
         * sets the content format for the ajax call
-        * 
-        * @param       string  can be one of the following keywords 'plain', '
+        *
+        * @param       string          can be one of 'plain' (default), 'xml', 'json', 'jsonbody' or 'jsonhead'
         * @return      void
         */
        public function setContentFormat($format) {
-               if (t3lib_div::inArray(array('plain', 'xml', 'json', 'jsonhead', 'jsonbody'), $format)) {
+               if (t3lib_div::inArray(array('plain', 'xml', 'json', 'jsonhead', 'jsonbody', 'javascript'), $format)) {
                        $this->contentFormat = $format;
                }
        }
@@ -132,7 +151,7 @@ class TYPO3AJAX {
        /**
         * sets an error message and the error flag
         *
-        * @param       string  the error message
+        * @param       string          the error message
         * @return      void
         */
        public function setError($errorMsg = '') {
@@ -144,7 +163,7 @@ class TYPO3AJAX {
        /**
         * checks whether an error occured during the execution or not
         *
-        * @return      boolean whether this AJAX call 
+        * @return      boolean         whether this AJAX call had errors
         */
        public function isError() {
                return $this->isError;
@@ -167,6 +186,9 @@ class TYPO3AJAX {
                        case 'json':
                                $this->renderAsJSON();
                                break;
+                       case 'javascript':
+                               $this->renderAsJavascript();
+                               break;
                        case 'xml':
                                $this->renderAsXML();
                                break;
@@ -180,10 +202,11 @@ class TYPO3AJAX {
        /**
         * renders the AJAX call in XML error style to handle with JS
         * the "responseXML" of the transport object will be filled with the error message then
-        * 
+        *
         * @return      void
         */
-       private function renderAsError() {
+       protected function renderAsError() {
+               header(t3lib_div::HTTP_STATUS_500 . ' (AJAX)');
                header('Content-type: text/xml; charset='.$this->charset);
                header('X-JSON: false');
                die('<t3err>'.htmlspecialchars($this->errorMessage).'</t3err>');
@@ -193,10 +216,10 @@ class TYPO3AJAX {
        /**
         * renders the AJAX call with text/html headers
         * the content will be available in the "responseText" value of the transport object
-        * 
+        *
         * @return      void
         */
-       private function renderAsPlain() {
+       protected function renderAsPlain() {
                header('Content-type: text/html; charset='.$this->charset);
                header('X-JSON: true');
                echo implode('', $this->content);
@@ -206,10 +229,10 @@ class TYPO3AJAX {
        /**
         * renders the AJAX call with text/xml headers
         * the content will be available in the "responseXML" value of the transport object
-        * 
+        *
         * @return      void
         */
-       private function renderAsXML() {
+       protected function renderAsXML() {
                header('Content-type: text/xml; charset='.$this->charset);
                header('X-JSON: true');
                echo implode('', $this->content);
@@ -220,16 +243,16 @@ class TYPO3AJAX {
         * renders the AJAX call with JSON evaluated headers
         * note that you need to have requestHeaders: {Accept: 'application/json'},
         * in your AJAX options of your AJAX request object in JS
-        * 
-        * the content will be available        
+        *
+        * the content will be available
         *    - in the second parameter of the onSuccess / onComplete callback (except when contentFormat = 'jsonbody')
         *    - and in the xhr.responseText as a string (except when contentFormat = 'jsonhead')
         *         you can evaluate this in JS with xhr.responseText.evalJSON();
         *
         * @return      void
         */
-       private function renderAsJSON() {
-               $content = t3lib_div::array2json($this->content);
+       protected function renderAsJSON() {
+               $content = json_encode($this->content);
 
                header('Content-type: application/json; charset='.$this->charset);
                header('X-JSON: '.($this->contentFormat != 'jsonbody' ? $content : true));
@@ -239,6 +262,25 @@ class TYPO3AJAX {
                        echo $content;
                }
        }
+
+       /**
+        * Renders the AJAX call as inline JSON inside a script tag. This is useful
+        * when an iframe is used as the AJAX transport.
+        *
+        * @return       void
+        */
+       protected function renderAsJavascript() {
+               $content = '<script type="text/javascript">
+                                       /*<![CDATA[*/
+
+                                       response = ' . json_encode($this->content) . ';
+
+                                       /*]]>*/
+                                       </script>';
+
+               header('Content-type: text/html; charset=' . $this->charset);
+               echo $content;
+       }
 }
 
 
@@ -246,4 +288,4 @@ if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/class
        include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/classes/class.typo3ajax.php']);
 }
 
-?>
+?>
\ No newline at end of file