--- /dev/null
+<?php\r
+/*\r
+* Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.\r
+* For licensing, see LICENSE.html or http://ckeditor.com/license\r
+*/\r
+\r
+/**\r
+ * \brief CKEditor class that can be used to create editor\r
+ * instances in PHP pages on server side.\r
+ * @see http://ckeditor.com\r
+ *\r
+ * Sample usage:\r
+ * @code\r
+ * $CKEditor = new CKEditor();\r
+ * $CKEditor->editor("editor1", "<p>Initial value.</p>");\r
+ * @endcode\r
+ */\r
+class CKEditor\r
+{\r
+ /**\r
+ * The version of %CKEditor.\r
+ */\r
+ const version = '3.6.1';\r
+ /**\r
+ * A constant string unique for each release of %CKEditor.\r
+ */\r
+ const timestamp = 'B5GJ5GG';\r
+\r
+ /**\r
+ * URL to the %CKEditor installation directory (absolute or relative to document root).\r
+ * If not set, CKEditor will try to guess it's path.\r
+ *\r
+ * Example usage:\r
+ * @code\r
+ * $CKEditor->basePath = '/ckeditor/';\r
+ * @endcode\r
+ */\r
+ public $basePath;\r
+ /**\r
+ * An array that holds the global %CKEditor configuration.\r
+ * For the list of available options, see http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html\r
+ *\r
+ * Example usage:\r
+ * @code\r
+ * $CKEditor->config['height'] = 400;\r
+ * // Use @@ at the beggining of a string to ouput it without surrounding quotes.\r
+ * $CKEditor->config['width'] = '@@screen.width * 0.8';\r
+ * @endcode\r
+ */\r
+ public $config = array();\r
+ /**\r
+ * A boolean variable indicating whether CKEditor has been initialized.\r
+ * Set it to true only if you have already included\r
+ * <script> tag loading ckeditor.js in your website.\r
+ */\r
+ public $initialized = false;\r
+ /**\r
+ * Boolean variable indicating whether created code should be printed out or returned by a function.\r
+ *\r
+ * Example 1: get the code creating %CKEditor instance and print it on a page with the "echo" function.\r
+ * @code\r
+ * $CKEditor = new CKEditor();\r
+ * $CKEditor->returnOutput = true;\r
+ * $code = $CKEditor->editor("editor1", "<p>Initial value.</p>");\r
+ * echo "<p>Editor 1:</p>";\r
+ * echo $code;\r
+ * @endcode\r
+ */\r
+ public $returnOutput = false;\r
+ /**\r
+ * An array with textarea attributes.\r
+ *\r
+ * When %CKEditor is created with the editor() method, a HTML <textarea> element is created,\r
+ * it will be displayed to anyone with JavaScript disabled or with incompatible browser.\r
+ */\r
+ public $textareaAttributes = array( "rows" => 8, "cols" => 60 );\r
+ /**\r
+ * A string indicating the creation date of %CKEditor.\r
+ * Do not change it unless you want to force browsers to not use previously cached version of %CKEditor.\r
+ */\r
+ public $timestamp = "B5GJ5GG";\r
+ /**\r
+ * An array that holds event listeners.\r
+ */\r
+ private $events = array();\r
+ /**\r
+ * An array that holds global event listeners.\r
+ */\r
+ private $globalEvents = array();\r
+\r
+ /**\r
+ * Main Constructor.\r
+ *\r
+ * @param $basePath (string) URL to the %CKEditor installation directory (optional).\r
+ */\r
+ function __construct($basePath = null) {\r
+ if (!empty($basePath)) {\r
+ $this->basePath = $basePath;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Creates a %CKEditor instance.\r
+ * In incompatible browsers %CKEditor will downgrade to plain HTML <textarea> element.\r
+ *\r
+ * @param $name (string) Name of the %CKEditor instance (this will be also the "name" attribute of textarea element).\r
+ * @param $value (string) Initial value (optional).\r
+ * @param $config (array) The specific configurations to apply to this editor instance (optional).\r
+ * @param $events (array) Event listeners for this editor instance (optional).\r
+ *\r
+ * Example usage:\r
+ * @code\r
+ * $CKEditor = new CKEditor();\r
+ * $CKEditor->editor("field1", "<p>Initial value.</p>");\r
+ * @endcode\r
+ *\r
+ * Advanced example:\r
+ * @code\r
+ * $CKEditor = new CKEditor();\r
+ * $config = array();\r
+ * $config['toolbar'] = array(\r
+ * array( 'Source', '-', 'Bold', 'Italic', 'Underline', 'Strike' ),\r
+ * array( 'Image', 'Link', 'Unlink', 'Anchor' )\r
+ * );\r
+ * $events['instanceReady'] = 'function (ev) {\r
+ * alert("Loaded: " + ev.editor.name);\r
+ * }';\r
+ * $CKEditor->editor("field1", "<p>Initial value.</p>", $config, $events);\r
+ * @endcode\r
+ */\r
+ public function editor($name, $value = "", $config = array(), $events = array())\r
+ {\r
+ $attr = "";\r
+ foreach ($this->textareaAttributes as $key => $val) {\r
+ $attr.= " " . $key . '="' . str_replace('"', '"', $val) . '"';\r
+ }\r
+ $out = "<textarea name=\"" . $name . "\"" . $attr . ">" . htmlspecialchars($value) . "</textarea>\n";\r
+ if (!$this->initialized) {\r
+ $out .= $this->init();\r
+ }\r
+\r
+ $_config = $this->configSettings($config, $events);\r
+\r
+ $js = $this->returnGlobalEvents();\r
+ if (!empty($_config))\r
+ $js .= "CKEDITOR.replace('".$name."', ".$this->jsEncode($_config).");";\r
+ else\r
+ $js .= "CKEDITOR.replace('".$name."');";\r
+\r
+ $out .= $this->script($js);\r
+\r
+ if (!$this->returnOutput) {\r
+ print $out;\r
+ $out = "";\r
+ }\r
+\r
+ return $out;\r
+ }\r
+\r
+ /**\r
+ * Replaces a <textarea> with a %CKEditor instance.\r
+ *\r
+ * @param $id (string) The id or name of textarea element.\r
+ * @param $config (array) The specific configurations to apply to this editor instance (optional).\r
+ * @param $events (array) Event listeners for this editor instance (optional).\r
+ *\r
+ * Example 1: adding %CKEditor to <textarea name="article"></textarea> element:\r
+ * @code\r
+ * $CKEditor = new CKEditor();\r
+ * $CKEditor->replace("article");\r
+ * @endcode\r
+ */\r
+ public function replace($id, $config = array(), $events = array())\r
+ {\r
+ $out = "";\r
+ if (!$this->initialized) {\r
+ $out .= $this->init();\r
+ }\r
+\r
+ $_config = $this->configSettings($config, $events);\r
+\r
+ $js = $this->returnGlobalEvents();\r
+ if (!empty($_config)) {\r
+ $js .= "CKEDITOR.replace('".$id."', ".$this->jsEncode($_config).");";\r
+ }\r
+ else {\r
+ $js .= "CKEDITOR.replace('".$id."');";\r
+ }\r
+ $out .= $this->script($js);\r
+\r
+ if (!$this->returnOutput) {\r
+ print $out;\r
+ $out = "";\r
+ }\r
+\r
+ return $out;\r
+ }\r
+\r
+ /**\r
+ * Replace all <textarea> elements available in the document with editor instances.\r
+ *\r
+ * @param $className (string) If set, replace all textareas with class className in the page.\r
+ *\r
+ * Example 1: replace all <textarea> elements in the page.\r
+ * @code\r
+ * $CKEditor = new CKEditor();\r
+ * $CKEditor->replaceAll();\r
+ * @endcode\r
+ *\r
+ * Example 2: replace all <textarea class="myClassName"> elements in the page.\r
+ * @code\r
+ * $CKEditor = new CKEditor();\r
+ * $CKEditor->replaceAll( 'myClassName' );\r
+ * @endcode\r
+ */\r
+ public function replaceAll($className = null)\r
+ {\r
+ $out = "";\r
+ if (!$this->initialized) {\r
+ $out .= $this->init();\r
+ }\r
+\r
+ $_config = $this->configSettings();\r
+\r
+ $js = $this->returnGlobalEvents();\r
+ if (empty($_config)) {\r
+ if (empty($className)) {\r
+ $js .= "CKEDITOR.replaceAll();";\r
+ }\r
+ else {\r
+ $js .= "CKEDITOR.replaceAll('".$className."');";\r
+ }\r
+ }\r
+ else {\r
+ $classDetection = "";\r
+ $js .= "CKEDITOR.replaceAll( function(textarea, config) {\n";\r
+ if (!empty($className)) {\r
+ $js .= " var classRegex = new RegExp('(?:^| )' + '". $className ."' + '(?:$| )');\n";\r
+ $js .= " if (!classRegex.test(textarea.className))\n";\r
+ $js .= " return false;\n";\r
+ }\r
+ $js .= " CKEDITOR.tools.extend(config, ". $this->jsEncode($_config) .", true);";\r
+ $js .= "} );";\r
+\r
+ }\r
+\r
+ $out .= $this->script($js);\r
+\r
+ if (!$this->returnOutput) {\r
+ print $out;\r
+ $out = "";\r
+ }\r
+\r
+ return $out;\r
+ }\r
+\r
+ /**\r
+ * Adds event listener.\r
+ * Events are fired by %CKEditor in various situations.\r
+ *\r
+ * @param $event (string) Event name.\r
+ * @param $javascriptCode (string) Javascript anonymous function or function name.\r
+ *\r
+ * Example usage:\r
+ * @code\r
+ * $CKEditor->addEventHandler('instanceReady', 'function (ev) {\r
+ * alert("Loaded: " + ev.editor.name);\r
+ * }');\r
+ * @endcode\r
+ */\r
+ public function addEventHandler($event, $javascriptCode)\r
+ {\r
+ if (!isset($this->events[$event])) {\r
+ $this->events[$event] = array();\r
+ }\r
+ // Avoid duplicates.\r
+ if (!in_array($javascriptCode, $this->events[$event])) {\r
+ $this->events[$event][] = $javascriptCode;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Clear registered event handlers.\r
+ * Note: this function will have no effect on already created editor instances.\r
+ *\r
+ * @param $event (string) Event name, if not set all event handlers will be removed (optional).\r
+ */\r
+ public function clearEventHandlers($event = null)\r
+ {\r
+ if (!empty($event)) {\r
+ $this->events[$event] = array();\r
+ }\r
+ else {\r
+ $this->events = array();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Adds global event listener.\r
+ *\r
+ * @param $event (string) Event name.\r
+ * @param $javascriptCode (string) Javascript anonymous function or function name.\r
+ *\r
+ * Example usage:\r
+ * @code\r
+ * $CKEditor->addGlobalEventHandler('dialogDefinition', 'function (ev) {\r
+ * alert("Loading dialog: " + ev.data.name);\r
+ * }');\r
+ * @endcode\r
+ */\r
+ public function addGlobalEventHandler($event, $javascriptCode)\r
+ {\r
+ if (!isset($this->globalEvents[$event])) {\r
+ $this->globalEvents[$event] = array();\r
+ }\r
+ // Avoid duplicates.\r
+ if (!in_array($javascriptCode, $this->globalEvents[$event])) {\r
+ $this->globalEvents[$event][] = $javascriptCode;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Clear registered global event handlers.\r
+ * Note: this function will have no effect if the event handler has been already printed/returned.\r
+ *\r
+ * @param $event (string) Event name, if not set all event handlers will be removed (optional).\r
+ */\r
+ public function clearGlobalEventHandlers($event = null)\r
+ {\r
+ if (!empty($event)) {\r
+ $this->globalEvents[$event] = array();\r
+ }\r
+ else {\r
+ $this->globalEvents = array();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Prints javascript code.\r
+ *\r
+ * @param string $js\r
+ */\r
+ private function script($js)\r
+ {\r
+ $out = "<script type=\"text/javascript\">";\r
+ $out .= "//<![CDATA[\n";\r
+ $out .= $js;\r
+ $out .= "\n//]]>";\r
+ $out .= "</script>\n";\r
+\r
+ return $out;\r
+ }\r
+\r
+ /**\r
+ * Returns the configuration array (global and instance specific settings are merged into one array).\r
+ *\r
+ * @param $config (array) The specific configurations to apply to editor instance.\r
+ * @param $events (array) Event listeners for editor instance.\r
+ */\r
+ private function configSettings($config = array(), $events = array())\r
+ {\r
+ $_config = $this->config;\r
+ $_events = $this->events;\r
+\r
+ if (is_array($config) && !empty($config)) {\r
+ $_config = array_merge($_config, $config);\r
+ }\r
+\r
+ if (is_array($events) && !empty($events)) {\r
+ foreach ($events as $eventName => $code) {\r
+ if (!isset($_events[$eventName])) {\r
+ $_events[$eventName] = array();\r
+ }\r
+ if (!in_array($code, $_events[$eventName])) {\r
+ $_events[$eventName][] = $code;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (!empty($_events)) {\r
+ foreach($_events as $eventName => $handlers) {\r
+ if (empty($handlers)) {\r
+ continue;\r
+ }\r
+ else if (count($handlers) == 1) {\r
+ $_config['on'][$eventName] = '@@'.$handlers[0];\r
+ }\r
+ else {\r
+ $_config['on'][$eventName] = '@@function (ev){';\r
+ foreach ($handlers as $handler => $code) {\r
+ $_config['on'][$eventName] .= '('.$code.')(ev);';\r
+ }\r
+ $_config['on'][$eventName] .= '}';\r
+ }\r
+ }\r
+ }\r
+\r
+ return $_config;\r
+ }\r
+\r
+ /**\r
+ * Return global event handlers.\r
+ */\r
+ private function returnGlobalEvents()\r
+ {\r
+ static $returnedEvents;\r
+ $out = "";\r
+\r
+ if (!isset($returnedEvents)) {\r
+ $returnedEvents = array();\r
+ }\r
+\r
+ if (!empty($this->globalEvents)) {\r
+ foreach ($this->globalEvents as $eventName => $handlers) {\r
+ foreach ($handlers as $handler => $code) {\r
+ if (!isset($returnedEvents[$eventName])) {\r
+ $returnedEvents[$eventName] = array();\r
+ }\r
+ // Return only new events\r
+ if (!in_array($code, $returnedEvents[$eventName])) {\r
+ $out .= ($code ? "\n" : "") . "CKEDITOR.on('". $eventName ."', $code);";\r
+ $returnedEvents[$eventName][] = $code;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ return $out;\r
+ }\r
+\r
+ /**\r
+ * Initializes CKEditor (executed only once).\r
+ */\r
+ private function init()\r
+ {\r
+ static $initComplete;\r
+ $out = "";\r
+\r
+ if (!empty($initComplete)) {\r
+ return "";\r
+ }\r
+\r
+ if ($this->initialized) {\r
+ $initComplete = true;\r
+ return "";\r
+ }\r
+\r
+ $args = "";\r
+ $ckeditorPath = $this->ckeditorPath();\r
+\r
+ if (!empty($this->timestamp) && $this->timestamp != "%"."TIMESTAMP%") {\r
+ $args = '?t=' . $this->timestamp;\r
+ }\r
+\r
+ // Skip relative paths...\r
+ if (strpos($ckeditorPath, '..') !== 0) {\r
+ $out .= $this->script("window.CKEDITOR_BASEPATH='". $ckeditorPath ."';");\r
+ }\r
+\r
+ $out .= "<script type=\"text/javascript\" src=\"" . $ckeditorPath . 'ckeditor.js' . $args . "\"></script>\n";\r
+\r
+ $extraCode = "";\r
+ if ($this->timestamp != self::timestamp) {\r
+ $extraCode .= ($extraCode ? "\n" : "") . "CKEDITOR.timestamp = '". $this->timestamp ."';";\r
+ }\r
+ if ($extraCode) {\r
+ $out .= $this->script($extraCode);\r
+ }\r
+\r
+ $initComplete = $this->initialized = true;\r
+\r
+ return $out;\r
+ }\r
+\r
+ /**\r
+ * Return path to ckeditor.js.\r
+ */\r
+ private function ckeditorPath()\r
+ {\r
+ if (!empty($this->basePath)) {\r
+ return $this->basePath;\r
+ }\r
+\r
+ /**\r
+ * The absolute pathname of the currently executing script.\r
+ * Note: If a script is executed with the CLI, as a relative path, such as file.php or ../file.php,\r
+ * $_SERVER['SCRIPT_FILENAME'] will contain the relative path specified by the user.\r
+ */\r
+ if (isset($_SERVER['SCRIPT_FILENAME'])) {\r
+ $realPath = dirname($_SERVER['SCRIPT_FILENAME']);\r
+ }\r
+ else {\r
+ /**\r
+ * realpath - Returns canonicalized absolute pathname\r
+ */\r
+ $realPath = realpath( './' ) ;\r
+ }\r
+\r
+ /**\r
+ * The filename of the currently executing script, relative to the document root.\r
+ * For instance, $_SERVER['PHP_SELF'] in a script at the address http://example.com/test.php/foo.bar\r
+ * would be /test.php/foo.bar.\r
+ */\r
+ $selfPath = dirname($_SERVER['PHP_SELF']);\r
+ $file = str_replace("\\", "/", __FILE__);\r
+\r
+ if (!$selfPath || !$realPath || !$file) {\r
+ return "/ckeditor/";\r
+ }\r
+\r
+ $documentRoot = substr($realPath, 0, strlen($realPath) - strlen($selfPath));\r
+ $fileUrl = substr($file, strlen($documentRoot));\r
+ $ckeditorUrl = str_replace("ckeditor_php5.php", "", $fileUrl);\r
+\r
+ return $ckeditorUrl;\r
+ }\r
+\r
+ /**\r
+ * This little function provides a basic JSON support.\r
+ *\r
+ * @param mixed $val\r
+ * @return string\r
+ */\r
+ private function jsEncode($val)\r
+ {\r
+ if (is_null($val)) {\r
+ return 'null';\r
+ }\r
+ if (is_bool($val)) {\r
+ return $val ? 'true' : 'false';\r
+ }\r
+ if (is_int($val)) {\r
+ return $val;\r
+ }\r
+ if (is_float($val)) {\r
+ return str_replace(',', '.', $val);\r
+ }\r
+ if (is_array($val) || is_object($val)) {\r
+ if (is_array($val) && (array_keys($val) === range(0,count($val)-1))) {\r
+ return '[' . implode(',', array_map(array($this, 'jsEncode'), $val)) . ']';\r
+ }\r
+ $temp = array();\r
+ foreach ($val as $k => $v){\r
+ $temp[] = $this->jsEncode("{$k}") . ':' . $this->jsEncode($v);\r
+ }\r
+ return '{' . implode(',', $temp) . '}';\r
+ }\r
+ // String otherwise\r
+ if (strpos($val, '@@') === 0)\r
+ return substr($val, 2);\r
+ if (strtoupper(substr($val, 0, 9)) == 'CKEDITOR.')\r
+ return $val;\r
+\r
+ return '"' . str_replace(array("\\", "/", "\n", "\t", "\r", "\x08", "\x0c", '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'), $val) . '"';\r
+ }\r
+}\r