text changes to registration mail content
[namibia] / public / scripts / ckeditor / ckeditor_php5.php
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.2';
24         /**
25          * A constant string unique for each release of %CKEditor.
26          */
27         const timestamp = 'B8DJ5M3';
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 = "B8DJ5M3";
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 }