openrat-cms

# OpenRat Content Management System
git clone http://git.code.weiherhei.de/openrat-cms.git
Log | Files | Refs

ckeditor_php4.php (16070B)


      1 <?php
      2 /*
      3 * Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
      4 * For licensing, see LICENSE.html or http://ckeditor.com/license
      5 */
      6 
      7 /**
      8  * \brief CKEditor class that can be used to create editor
      9  * instances in PHP pages on server side.
     10  * @see http://ckeditor.com
     11  *
     12  * Sample usage:
     13  * @code
     14  * $CKEditor = new CKEditor();
     15  * $CKEditor->editor("editor1", "<p>Initial value.</p>");
     16  * @endcode
     17  */
     18 class CKEditor
     19 {
     20 	/**
     21 	 * The version of %CKEditor.
     22 	 * \private
     23 	 */
     24 	var $version = '3.5.2';
     25 	/**
     26 	 * A constant string unique for each release of %CKEditor.
     27 	 * \private
     28 	 */
     29 	var $_timestamp = 'B1GG4Z6';
     30 
     31 	/**
     32 	 * URL to the %CKEditor installation directory (absolute or relative to document root).
     33 	 * If not set, CKEditor will try to guess it's path.
     34 	 *
     35 	 * Example usage:
     36 	 * @code
     37 	 * $CKEditor->basePath = '/ckeditor/';
     38 	 * @endcode
     39 	 */
     40 	var $basePath;
     41 	/**
     42 	 * An array that holds the global %CKEditor configuration.
     43 	 * For the list of available options, see http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html
     44 	 *
     45 	 * Example usage:
     46 	 * @code
     47 	 * $CKEditor->config['height'] = 400;
     48 	 * // Use @@ at the beggining of a string to ouput it without surrounding quotes.
     49 	 * $CKEditor->config['width'] = '@@screen.width * 0.8';
     50 	 * @endcode
     51 	 */
     52 	var $config = array();
     53 	/**
     54 	 * A boolean variable indicating whether CKEditor has been initialized.
     55 	 * Set it to true only if you have already included
     56 	 * &lt;script&gt; tag loading ckeditor.js in your website.
     57 	 */
     58 	var $initialized = false;
     59 	/**
     60 	 * Boolean variable indicating whether created code should be printed out or returned by a function.
     61 	 *
     62 	 * Example 1: get the code creating %CKEditor instance and print it on a page with the "echo" function.
     63 	 * @code
     64 	 * $CKEditor = new CKEditor();
     65 	 * $CKEditor->returnOutput = true;
     66 	 * $code = $CKEditor->editor("editor1", "<p>Initial value.</p>");
     67 	 * echo "<p>Editor 1:</p>";
     68 	 * echo $code;
     69 	 * @endcode
     70 	 */
     71 	var $returnOutput = false;
     72 	/**
     73 	 * An array with textarea attributes.
     74 	 *
     75 	 * When %CKEditor is created with the editor() method, a HTML &lt;textarea&gt; element is created,
     76 	 * it will be displayed to anyone with JavaScript disabled or with incompatible browser.
     77 	 */
     78 	var $textareaAttributes = array( "rows" => 8, "cols" => 60 );
     79 	/**
     80 	 * A string indicating the creation date of %CKEditor.
     81 	 * Do not change it unless you want to force browsers to not use previously cached version of %CKEditor.
     82 	 */
     83 	var $timestamp = "B1GG4Z6";
     84 	/**
     85 	 * An array that holds event listeners.
     86 	 * \private
     87 	 */
     88 	var $_events = array();
     89 	/**
     90 	 * An array that holds global event listeners.
     91 	 * \private
     92 	 */
     93 	var $_globalEvents = array();
     94 
     95 	/**
     96 	 * Main Constructor.
     97 	 *
     98 	 *  @param $basePath (string) URL to the %CKEditor installation directory (optional).
     99 	 */
    100 	function CKEditor($basePath = null) {
    101 		if (!empty($basePath)) {
    102 			$this->basePath = $basePath;
    103 		}
    104 	}
    105 
    106 	/**
    107 	 * Creates a %CKEditor instance.
    108 	 * In incompatible browsers %CKEditor will downgrade to plain HTML &lt;textarea&gt; element.
    109 	 *
    110 	 * @param $name (string) Name of the %CKEditor instance (this will be also the "name" attribute of textarea element).
    111 	 * @param $value (string) Initial value (optional).
    112 	 * @param $config (array) The specific configurations to apply to this editor instance (optional).
    113 	 * @param $events (array) Event listeners for this editor instance (optional).
    114 	 *
    115 	 * Example usage:
    116 	 * @code
    117 	 * $CKEditor = new CKEditor();
    118 	 * $CKEditor->editor("field1", "<p>Initial value.</p>");
    119 	 * @endcode
    120 	 *
    121 	 * Advanced example:
    122 	 * @code
    123 	 * $CKEditor = new CKEditor();
    124 	 * $config = array();
    125 	 * $config['toolbar'] = array(
    126 	 *     array( 'Source', '-', 'Bold', 'Italic', 'Underline', 'Strike' ),
    127 	 *     array( 'Image', 'Link', 'Unlink', 'Anchor' )
    128 	 * );
    129 	 * $events['instanceReady'] = 'function (ev) {
    130 	 *     alert("Loaded: " + ev.editor.name);
    131 	 * }';
    132 	 * $CKEditor->editor("field1", "<p>Initial value.</p>", $config, $events);
    133 	 * @endcode
    134 	 */
    135 	function editor($name, $value = "", $config = array(), $events = array())
    136 	{
    137 		$attr = "";
    138 		foreach ($this->textareaAttributes as $key => $val) {
    139 			$attr.= " " . $key . '="' . str_replace('"', '&quot;', $val) . '"';
    140 		}
    141 		$out = "<textarea name=\"" . $name . "\"" . $attr . ">" . htmlspecialchars($value) . "</textarea>\n";
    142 		if (!$this->initialized) {
    143 			$out .= $this->init();
    144 		}
    145 
    146 		$_config = $this->configSettings($config, $events);
    147 
    148 		$js = $this->returnGlobalEvents();
    149 		if (!empty($_config))
    150 			$js .= "CKEDITOR.replace('".$name."', ".$this->jsEncode($_config).");";
    151 		else
    152 			$js .= "CKEDITOR.replace('".$name."');";
    153 
    154 		$out .= $this->script($js);
    155 
    156 		if (!$this->returnOutput) {
    157 			print $out;
    158 			$out = "";
    159 		}
    160 
    161 		return $out;
    162 	}
    163 
    164 	/**
    165 	 * Replaces a &lt;textarea&gt; with a %CKEditor instance.
    166 	 *
    167 	 * @param $id (string) The id or name of textarea element.
    168 	 * @param $config (array) The specific configurations to apply to this editor instance (optional).
    169 	 * @param $events (array) Event listeners for this editor instance (optional).
    170 	 *
    171 	 * Example 1: adding %CKEditor to &lt;textarea name="article"&gt;&lt;/textarea&gt; element:
    172 	 * @code
    173 	 * $CKEditor = new CKEditor();
    174 	 * $CKEditor->replace("article");
    175 	 * @endcode
    176 	 */
    177 	function replace($id, $config = array(), $events = array())
    178 	{
    179 		$out = "";
    180 		if (!$this->initialized) {
    181 			$out .= $this->init();
    182 		}
    183 
    184 		$_config = $this->configSettings($config, $events);
    185 
    186 		$js = $this->returnGlobalEvents();
    187 		if (!empty($_config)) {
    188 			$js .= "CKEDITOR.replace('".$id."', ".$this->jsEncode($_config).");";
    189 		}
    190 		else {
    191 			$js .= "CKEDITOR.replace('".$id."');";
    192 		}
    193 		$out .= $this->script($js);
    194 
    195 		if (!$this->returnOutput) {
    196 			print $out;
    197 			$out = "";
    198 		}
    199 
    200 		return $out;
    201 	}
    202 
    203 	/**
    204 	 * Replace all &lt;textarea&gt; elements available in the document with editor instances.
    205 	 *
    206 	 * @param $className (string) If set, replace all textareas with class className in the page.
    207 	 *
    208 	 * Example 1: replace all &lt;textarea&gt; elements in the page.
    209 	 * @code
    210 	 * $CKEditor = new CKEditor();
    211 	 * $CKEditor->replaceAll();
    212 	 * @endcode
    213 	 *
    214 	 * Example 2: replace all &lt;textarea class="myClassName"&gt; elements in the page.
    215 	 * @code
    216 	 * $CKEditor = new CKEditor();
    217 	 * $CKEditor->replaceAll( 'myClassName' );
    218 	 * @endcode
    219 	 */
    220 	function replaceAll($className = null)
    221 	{
    222 		$out = "";
    223 		if (!$this->initialized) {
    224 			$out .= $this->init();
    225 		}
    226 
    227 		$_config = $this->configSettings();
    228 
    229 		$js = $this->returnGlobalEvents();
    230 		if (empty($_config)) {
    231 			if (empty($className)) {
    232 				$js .= "CKEDITOR.replaceAll();";
    233 			}
    234 			else {
    235 				$js .= "CKEDITOR.replaceAll('".$className."');";
    236 			}
    237 		}
    238 		else {
    239 			$classDetection = "";
    240 			$js .= "CKEDITOR.replaceAll( function(textarea, config) {\n";
    241 			if (!empty($className)) {
    242 				$js .= "	var classRegex = new RegExp('(?:^| )' + '". $className ."' + '(?:$| )');\n";
    243 				$js .= "	if (!classRegex.test(textarea.className))\n";
    244 				$js .= "		return false;\n";
    245 			}
    246 			$js .= "	CKEDITOR.tools.extend(config, ". $this->jsEncode($_config) .", true);";
    247 			$js .= "} );";
    248 
    249 		}
    250 
    251 		$out .= $this->script($js);
    252 
    253 		if (!$this->returnOutput) {
    254 			print $out;
    255 			$out = "";
    256 		}
    257 
    258 		return $out;
    259 	}
    260 
    261 	/**
    262 	 * Adds event listener.
    263 	 * Events are fired by %CKEditor in various situations.
    264 	 *
    265 	 * @param $event (string) Event name.
    266 	 * @param $javascriptCode (string) Javascript anonymous function or function name.
    267 	 *
    268 	 * Example usage:
    269 	 * @code
    270 	 * $CKEditor->addEventHandler('instanceReady', 'function (ev) {
    271 	 *     alert("Loaded: " + ev.editor.name);
    272 	 * }');
    273 	 * @endcode
    274 	 */
    275 	function addEventHandler($event, $javascriptCode)
    276 	{
    277 		if (!isset($this->_events[$event])) {
    278 			$this->_events[$event] = array();
    279 		}
    280 		// Avoid duplicates.
    281 		if (!in_array($javascriptCode, $this->_events[$event])) {
    282 			$this->_events[$event][] = $javascriptCode;
    283 		}
    284 	}
    285 
    286 	/**
    287 	 * Clear registered event handlers.
    288 	 * Note: this function will have no effect on already created editor instances.
    289 	 *
    290 	 * @param $event (string) Event name, if not set all event handlers will be removed (optional).
    291 	 */
    292 	function clearEventHandlers($event = null)
    293 	{
    294 		if (!empty($event)) {
    295 			$this->_events[$event] = array();
    296 		}
    297 		else {
    298 			$this->_events = array();
    299 		}
    300 	}
    301 
    302 	/**
    303 	 * Adds global event listener.
    304 	 *
    305 	 * @param $event (string) Event name.
    306 	 * @param $javascriptCode (string) Javascript anonymous function or function name.
    307 	 *
    308 	 * Example usage:
    309 	 * @code
    310 	 * $CKEditor->addGlobalEventHandler('dialogDefinition', 'function (ev) {
    311 	 *     alert("Loading dialog: " + ev.data.name);
    312 	 * }');
    313 	 * @endcode
    314 	 */
    315 	function addGlobalEventHandler($event, $javascriptCode)
    316 	{
    317 		if (!isset($this->_globalEvents[$event])) {
    318 			$this->_globalEvents[$event] = array();
    319 		}
    320 		// Avoid duplicates.
    321 		if (!in_array($javascriptCode, $this->_globalEvents[$event])) {
    322 			$this->_globalEvents[$event][] = $javascriptCode;
    323 		}
    324 	}
    325 
    326 	/**
    327 	 * Clear registered global event handlers.
    328 	 * Note: this function will have no effect if the event handler has been already printed/returned.
    329 	 *
    330 	 * @param $event (string) Event name, if not set all event handlers will be removed (optional).
    331 	 */
    332 	function clearGlobalEventHandlers($event = null)
    333 	{
    334 		if (!empty($event)) {
    335 			$this->_globalEvents[$event] = array();
    336 		}
    337 		else {
    338 			$this->_globalEvents = array();
    339 		}
    340 	}
    341 
    342 	/**
    343 	 * Prints javascript code.
    344 	 * \private
    345 	 *
    346 	 * @param string $js
    347 	 */
    348 	function script($js)
    349 	{
    350 		$out = "<script type=\"text/javascript\">";
    351 		$out .= "//<![CDATA[\n";
    352 		$out .= $js;
    353 		$out .= "\n//]]>";
    354 		$out .= "</script>\n";
    355 
    356 		return $out;
    357 	}
    358 
    359 	/**
    360 	 * Returns the configuration array (global and instance specific settings are merged into one array).
    361 	 * \private
    362 	 *
    363 	 * @param $config (array) The specific configurations to apply to editor instance.
    364 	 * @param $events (array) Event listeners for editor instance.
    365 	 */
    366 	function configSettings($config = array(), $events = array())
    367 	{
    368 		$_config = $this->config;
    369 		$_events = $this->_events;
    370 
    371 		if (is_array($config) && !empty($config)) {
    372 			$_config = array_merge($_config, $config);
    373 		}
    374 
    375 		if (is_array($events) && !empty($events)) {
    376 			foreach ($events as $eventName => $code) {
    377 				if (!isset($_events[$eventName])) {
    378 					$_events[$eventName] = array();
    379 				}
    380 				if (!in_array($code, $_events[$eventName])) {
    381 					$_events[$eventName][] = $code;
    382 				}
    383 			}
    384 		}
    385 
    386 		if (!empty($_events)) {
    387 			foreach($_events as $eventName => $handlers) {
    388 				if (empty($handlers)) {
    389 					continue;
    390 				}
    391 				else if (count($handlers) == 1) {
    392 					$_config['on'][$eventName] = '@@'.$handlers[0];
    393 				}
    394 				else {
    395 					$_config['on'][$eventName] = '@@function (ev){';
    396 					foreach ($handlers as $handler => $code) {
    397 						$_config['on'][$eventName] .= '('.$code.')(ev);';
    398 					}
    399 					$_config['on'][$eventName] .= '}';
    400 				}
    401 			}
    402 		}
    403 
    404 		return $_config;
    405 	}
    406 
    407 	/**
    408 	 * Return global event handlers.
    409 	 * \private
    410 	 */
    411 	function returnGlobalEvents()
    412 	{
    413 		static $returnedEvents;
    414 		$out = "";
    415 
    416 		if (!isset($returnedEvents)) {
    417 			$returnedEvents = array();
    418 		}
    419 
    420 		if (!empty($this->_globalEvents)) {
    421 			foreach ($this->_globalEvents as $eventName => $handlers) {
    422 				foreach ($handlers as $handler => $code) {
    423 					if (!isset($returnedEvents[$eventName])) {
    424 						$returnedEvents[$eventName] = array();
    425 					}
    426 					// Return only new events
    427 					if (!in_array($code, $returnedEvents[$eventName])) {
    428 						$out .= ($code ? "\n" : "") . "CKEDITOR.on('". $eventName ."', $code);";
    429 						$returnedEvents[$eventName][] = $code;
    430 					}
    431 				}
    432 			}
    433 		}
    434 
    435 		return $out;
    436 	}
    437 
    438 	/**
    439 	 * Initializes CKEditor (executed only once).
    440 	 * \private
    441 	 */
    442 	function init()
    443 	{
    444 		static $initComplete;
    445 		$out = "";
    446 
    447 		if (!empty($initComplete)) {
    448 			return "";
    449 		}
    450 
    451 		if ($this->initialized) {
    452 			$initComplete = true;
    453 			return "";
    454 		}
    455 
    456 		$args = "";
    457 		$ckeditorPath = $this->ckeditorPath();
    458 
    459 		if (!empty($this->timestamp) && $this->timestamp != "%"."TIMESTAMP%") {
    460 			$args = '?t=' . $this->timestamp;
    461 		}
    462 
    463 		// Skip relative paths...
    464 		if (strpos($ckeditorPath, '..') !== 0) {
    465 			$out .= $this->script("window.CKEDITOR_BASEPATH='". $ckeditorPath ."';");
    466 		}
    467 
    468 		$out .= "<script type=\"text/javascript\" src=\"" . $ckeditorPath . 'ckeditor.js' . $args . "\"></script>\n";
    469 
    470 		$extraCode = "";
    471 		if ($this->timestamp != $this->_timestamp) {
    472 			$extraCode .= ($extraCode ? "\n" : "") . "CKEDITOR.timestamp = '". $this->timestamp ."';";
    473 		}
    474 		if ($extraCode) {
    475 			$out .= $this->script($extraCode);
    476 		}
    477 
    478 		$initComplete = $this->initialized = true;
    479 
    480 		return $out;
    481 	}
    482 
    483 	/**
    484 	 * Return path to ckeditor.js.
    485 	 * \private
    486 	 */
    487 	function ckeditorPath()
    488 	{
    489 		if (!empty($this->basePath)) {
    490 			return $this->basePath;
    491 		}
    492 
    493 		/**
    494 		 * The absolute pathname of the currently executing script.
    495 		 * Note: If a script is executed with the CLI, as a relative path, such as file.php or ../file.php,
    496 		 * $_SERVER['SCRIPT_FILENAME'] will contain the relative path specified by the user.
    497 		 */
    498 		if (isset($_SERVER['SCRIPT_FILENAME'])) {
    499 			$realPath = dirname($_SERVER['SCRIPT_FILENAME']);
    500 		}
    501 		else {
    502 			/**
    503 			 * realpath - Returns canonicalized absolute pathname
    504 			 */
    505 			$realPath = realpath( './' ) ;
    506 		}
    507 
    508 		/**
    509 		 * The filename of the currently executing script, relative to the document root.
    510 		 * For instance, $_SERVER['PHP_SELF'] in a script at the address http://example.com/test.php/foo.bar
    511 		 * would be /test.php/foo.bar.
    512 		 */
    513 		$selfPath = dirname($_SERVER['PHP_SELF']);
    514 		$file = str_replace("\\", "/", __FILE__);
    515 
    516 		if (!$selfPath || !$realPath || !$file) {
    517 			return "/ckeditor/";
    518 		}
    519 
    520 		$documentRoot = substr($realPath, 0, strlen($realPath) - strlen($selfPath));
    521 		$fileUrl = substr($file, strlen($documentRoot));
    522 		$ckeditorUrl = str_replace("ckeditor_php4.php", "", $fileUrl);
    523 
    524 		return $ckeditorUrl;
    525 	}
    526 
    527 	/**
    528 	 * This little function provides a basic JSON support.
    529 	 * http://php.net/manual/en/function.json-encode.php
    530 	 * \private
    531 	 *
    532 	 * @param mixed $val
    533 	 * @return string
    534 	 */
    535 	function jsEncode($val)
    536 	{
    537 		if (is_null($val)) {
    538 			return 'null';
    539 		}
    540 		if ($val === false) {
    541 			return 'false';
    542 		}
    543 		if ($val === true) {
    544 			return 'true';
    545 		}
    546 		if (is_scalar($val))
    547 		{
    548 			if (is_float($val))
    549 			{
    550 				// Always use "." for floats.
    551 				$val = str_replace(",", ".", strval($val));
    552 			}
    553 
    554 			// Use @@ to not use quotes when outputting string value
    555 			if (strpos($val, '@@') === 0) {
    556 				return substr($val, 2);
    557 			}
    558 			else {
    559 				// All scalars are converted to strings to avoid indeterminism.
    560 				// PHP's "1" and 1 are equal for all PHP operators, but
    561 				// JS's "1" and 1 are not. So if we pass "1" or 1 from the PHP backend,
    562 				// we should get the same result in the JS frontend (string).
    563 				// Character replacements for JSON.
    564 				static $jsonReplaces = array(array("\\", "/", "\n", "\t", "\r", "\b", "\f", '"'),
    565 				array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'));
    566 
    567 				$val = str_replace($jsonReplaces[0], $jsonReplaces[1], $val);
    568 				if (strtoupper(substr($val, 0, 9)) == 'CKEDITOR.') {
    569 					return $val;
    570 				}
    571 
    572 				return '"' . $val . '"';
    573 			}
    574 		}
    575 		$isList = true;
    576 		for ($i = 0, reset($val); $i < count($val); $i++, next($val))
    577 		{
    578 			if (key($val) !== $i)
    579 			{
    580 				$isList = false;
    581 				break;
    582 			}
    583 		}
    584 		$result = array();
    585 		if ($isList)
    586 		{
    587 			foreach ($val as $v) $result[] = $this->jsEncode($v);
    588 			return '[ ' . join(', ', $result) . ' ]';
    589 		}
    590 		else
    591 		{
    592 			foreach ($val as $k => $v) $result[] = $this->jsEncode($k).': '.$this->jsEncode($v);
    593 			return '{ ' . join(', ', $result) . ' }';
    594 		}
    595 	}
    596 }