Advertisement
Guest User

Ckeditor

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