Przeglądaj źródła

Adds ckeditor integration see BT#8968

Julio Montoya 10 lat temu
rodzic
commit
bc3eb4a3cf
46 zmienionych plików z 3083 dodań i 129 usunięć
  1. 25 0
      main/inc/lib/elfinder/connectorAction.php
  2. 7 0
      main/inc/lib/elfinder/filemanager.php
  3. 17 0
      main/inc/lib/elfinder/templates.php
  4. 48 75
      main/inc/lib/formvalidator/Element/html_editor.php
  5. 9 31
      main/inc/lib/formvalidator/FormValidator.class.php
  6. 5 9
      main/inc/lib/template.lib.php
  7. 7 1
      main/newscorm/lp_add_item.php
  8. 10 5
      main/newscorm/lp_edit_item.php
  9. 21 0
      main/template/default/javascript/editor/ckeditor/config_js.tpl
  10. 35 0
      main/template/default/javascript/editor/ckeditor/elfinder.tpl
  11. 6 0
      main/template/default/javascript/editor/ckeditor/templates.tpl
  12. 0 4
      main/template/default/layout/footer.tpl
  13. 68 4
      main/template/default/layout/head.tpl
  14. 155 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/CkEditor.php
  15. 106 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Basic.php
  16. 58 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Documents.php
  17. 40 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/IntroductionTool.php
  18. 39 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/LearningPathDocuments.php
  19. 35 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Message.php
  20. 13 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Notebook.php
  21. 13 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/NotebookStudent.php
  22. 16 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/PortalHomePage.php
  23. 16 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/PortalNews.php
  24. 12 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/ProjectStudent.php
  25. 13 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestAnswerFeedback.php
  26. 50 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestFreeAnswer.php
  27. 54 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestFreeAnswerStrict.php
  28. 36 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestProposedAnswer.php
  29. 40 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestQuestionDescription.php
  30. 14 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/ToolbarStartExpanded.php
  31. 16 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TrainingDescription.php
  32. 36 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/UniqueAnswerImage.php
  33. 13 0
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/WikiStudent.php
  34. 397 0
      src/Chamilo/CoreBundle/Component/Editor/Connector.php
  35. 163 0
      src/Chamilo/CoreBundle/Component/Editor/Driver/CourseDriver.php
  36. 37 0
      src/Chamilo/CoreBundle/Component/Editor/Driver/CourseUserDriver.php
  37. 63 0
      src/Chamilo/CoreBundle/Component/Editor/Driver/Driver.php
  38. 41 0
      src/Chamilo/CoreBundle/Component/Editor/Driver/DriverInterface.php
  39. 641 0
      src/Chamilo/CoreBundle/Component/Editor/Driver/DropBoxDriver.php
  40. 54 0
      src/Chamilo/CoreBundle/Component/Editor/Driver/HomeDriver.php
  41. 62 0
      src/Chamilo/CoreBundle/Component/Editor/Driver/PersonalDriver.php
  42. 240 0
      src/Chamilo/CoreBundle/Component/Editor/Editor.php
  43. 112 0
      src/Chamilo/CoreBundle/Component/Editor/Finder.php
  44. 82 0
      src/Chamilo/CoreBundle/Component/Editor/TinyMce/TinyMce.php
  45. 38 0
      src/Chamilo/CoreBundle/Component/Editor/TinyMce/Toolbar/Basic.php
  46. 120 0
      src/Chamilo/CoreBundle/Component/Editor/Toolbar.php

+ 25 - 0
main/inc/lib/elfinder/connectorAction.php

@@ -0,0 +1,25 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+require_once '../../global.inc.php';
+
+use Chamilo\CoreBundle\Component\Editor\Connector;
+use Chamilo\CoreBundle\Component\Editor\Finder;
+
+error_reporting(-1);
+/** @var Connector $connector */
+$connector = new Connector();
+$driverList = array(
+    'PersonalDriver',
+    'CourseDriver',
+    'CourseUserDriver',
+    'HomeDriver'
+);
+$connector->setDriverList($driverList);
+
+$operations = $connector->getOperations();
+
+// Run elFinder
+$finder = new Finder($operations);
+$elFinderConnector = new \elFinderConnector($finder);
+$elFinderConnector->run();

+ 7 - 0
main/inc/lib/elfinder/filemanager.php

@@ -0,0 +1,7 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+require_once '../../global.inc.php';
+
+$template = new Template();
+$template->display('default/javascript/editor/ckeditor/elfinder.tpl');

+ 17 - 0
main/inc/lib/elfinder/templates.php

@@ -0,0 +1,17 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+require_once '../../global.inc.php';
+
+use Chamilo\CoreBundle\Component\Editor\CkEditor\CkEditor;
+
+$template = new Template();
+
+$table = Database::get_main_table(TABLE_MAIN_SYSTEM_TEMPLATE);
+$sql = "SELECT * FROM $table";
+$result = Database::query($sql);
+$templates = Database::store_result($result, 'ASSOC');
+$editor = new CkEditor();
+$templates = $editor->simpleFormatTemplates($templates);
+$template->assign('templates', $templates);
+$template->display('default/javascript/editor/ckeditor/templates.tpl');

+ 48 - 75
main/inc/lib/formvalidator/Element/html_editor.php

@@ -1,125 +1,98 @@
 <?php
-
 /* For licensing terms, see /license.txt */
 
-require_once 'HTML/QuickForm/textarea.php';
-require_once api_get_path(LIBRARY_PATH) . 'fckeditor/fckeditor.php';
+use \Chamilo\CoreBundle\Component\Editor\CkEditor\CkEditor;
 
 /**
  * A html editor field to use with QuickForm
  */
-class HTML_QuickForm_html_editor extends HTML_QuickForm_textarea {
+class HTML_QuickForm_html_editor extends HTML_QuickForm_textarea
+{
+    /** @var \Chamilo\CoreBundle\Component\Editor\Editor */
+    public $editor;
 
     /**
      * Full page
      */
     var $fullPage;
     var $fck_editor;
+    var $content;
 
     /**
      * Class constructor
-     * @param   string  HTML editor name/id
-     * @param   string  HTML editor  label
-     * @param   string  Attributes for the textarea
-     * @param array $editor_config	Optional configuration settings for the online editor.
+     * @param string  HTML editor name/id
+     * @param string  HTML editor  label
+     * @param array  Attributes for the textarea
+     * @param array $config	Optional configuration settings for the online editor.
+     * @return bool
      */
-    function HTML_QuickForm_html_editor($elementName = null, $elementLabel = null, $attributes = null, $config = null) {
-        // The global variable $fck_attribute has been deprecated. It stays here for supporting old external code.
-        global $fck_attribute;
+    public function HTML_QuickForm_html_editor($name = null, $elementLabel = null, $attributes = null, $config = null)
+    {
+        if (empty($name)) {
+            return false;
+        }
 
-        HTML_QuickForm_element :: HTML_QuickForm_element($elementName, $elementLabel, $attributes);
+        HTML_QuickForm_element :: HTML_QuickForm_element($name, $elementLabel, $attributes);
         $this->_persistantFreeze = true;
         $this->_type = 'html_editor';
-        $this->fullPage = false;
 
-        $name = $this->getAttribute('name');
-        $this->fck_editor = new FCKeditor($name);
-
-        $this->fck_editor->ToolbarSet = $fck_attribute['ToolbarSet'];
-        $this->fck_editor->Width = !empty($fck_attribute['Width']) ? $fck_attribute['Width'] : '990';
-        $this->fck_editor->Height = !empty($fck_attribute['Height']) ? $fck_attribute['Height'] : '400';
-        //We get the optionnals config parameters in $fck_attribute array
-        $this->fck_editor->Config = !empty($fck_attribute['Config']) ? $fck_attribute['Config'] : array();
+        global $fck_attribute;
 
-        // This is an alternative (a better) way to pass configuration data to the editor.
-        if (is_array($config)) {
-            foreach ($config as $key => $value) {
-                $this->fck_editor->Config[$key] = $config[$key];
-            }
-            if (isset($config['ToolbarSet'])) {
-                $this->fck_editor->ToolbarSet = $config['ToolbarSet'];
-            }
-            if (isset($config['Width'])) {
-                $this->fck_editor->Width = $config['Width'];
-            }
-            if (isset($config['Height'])) {
-                $this->fck_editor->Height = $config['Height'];
-            }
-            if (isset($config['FullPage'])) {
-                $this->fullPage = is_bool($config['FullPage']) ? $config['FullPage'] : ($config['FullPage'] === 'true');
-            }
+        //$editor = Container::getHtmlEditor();
+        $editor = new CkEditor();
+        if ($editor) {
+            $this->editor = $editor;
+            $this->editor->setName($name);
+            $this->editor->processConfig($fck_attribute);
+            $this->editor->processConfig($config);
         }
     }
 
-    /**
-     * Check if the browser supports FCKeditor
-     *
-     * @access public
-     * @return boolean
-     */
-    function browserSupported() {
-        return FCKeditor :: IsCompatible();
-    }
-
     /**
      * Return the HTML editor in HTML
      * @return string
      */
-    function toHtml() {
+    public function toHtml()
+    {
         $value = $this->getValue();
-        if ($this->fullPage) {
-            if (strlen(trim($value)) == 0) {
-                // TODO: To be considered whether here to be added DOCTYPE, language and character set declarations.
-                $value = '<html><head><title></title><style type="text/css" media="screen, projection">/*<![CDATA[*/body{font-family: arial, verdana, helvetica, sans-serif;font-size: 12px;}/*]]>*/</style></head><body></body></html>';
-                $this->setValue($value);
+        if ($this->editor) {
+            if ($this->editor->getConfigAttribute('fullPage')) {
+                if (strlen(trim($value)) == 0) {
+                    // TODO: To be considered whether here to be added DOCTYPE, language and character set declarations.
+                    $value = '<html><head><title></title></head><body></body></html>';
+                    $this->setValue($value);
+                }
             }
         }
-        if ($this->_flagFrozen) {
+
+        if ($this->isFrozen()) {
             return $this->getFrozenHtml();
         } else {
-            return $this->build_FCKeditor();
+            return $this->buildEditor();
         }
     }
 
     /**
-     * Returns the htmlarea content in HTML
+     * Returns the html area content in HTML
      * @return string
      */
-    function getFrozenHtml() {
+    public function getFrozenHtml()
+    {
         return $this->getValue();
     }
 
     /**
-     * Build this element using FCKeditor
+     * @return string
      */
-    function build_FCKeditor() {
-        if (!FCKeditor :: IsCompatible()) {
-            return parent::toHTML();
-        }
-        $this->fck_editor->Value = $this->getValue();
-        $result = $this->fck_editor->CreateHtml();
-
-        if (isset($this->fck_editor->Config['LoadAsciiMath'])) {
-            if (isset($_SESSION['ascii_math_loaded']) &&
-                $_SESSION['ascii_math_loaded'] == false
-            ) {
-                $result .= $this->fck_editor->Config['LoadAsciiMath'];
-                $_SESSION['ascii_math_loaded'] = true;
-            }
+    public function buildEditor()
+    {
+        $result = '';
+        if ($this->editor) {
+            $this->editor->value = $this->getValue();
+            $this->editor->setName($this->getName());
+            $result = $this->editor->createHtml();
         }
 
-        //Add a link to open the allowed html tags window
-        //$result .= '<small><a href="#" onclick="MyWindow=window.open('."'".api_get_path(WEB_CODE_PATH)."help/allowed_html_tags.php?fullpage=". ($this->fullPage ? '1' : '0')."','MyWindow','toolbar=no,location=no,directories=no,status=yes,menubar=no,scrollbars=yes,resizable=yes,width=500,height=600,left=200,top=20'".'); return false;">'.get_lang('AllowedHTMLTags').'</a></small>';
         return $result;
     }
 }

+ 9 - 31
main/inc/lib/formvalidator/FormValidator.class.php

@@ -1,9 +1,6 @@
 <?php
 /* For licensing terms, see /license.txt */
 
-require_once api_get_path(LIBRARY_PATH).'pear/HTML/QuickForm.php';
-require_once api_get_path(LIBRARY_PATH).'pear/HTML/QuickForm/advmultiselect.php';
-
 /**
  * Filter
  */
@@ -346,42 +343,23 @@ EOT;
      * @param string $label						The label for the form-element
      * @param boolean $required	(optional)		Is the form-element required (default=true)
      * @param boolean $full_page (optional)		When it is true, the editor loads completed html code for a full page.
-     * @param array $editor_config (optional)	Configuration settings for the online editor.
+     * @param array $config (optional)	Configuration settings for the online editor.
+     *
      */
-    function add_html_editor($name, $label, $required = true, $full_page = false, $config = null)
+    public function add_html_editor($name, $label, $required = true, $full_page = false, $config = null)
     {
         $this->addElement('html_editor', $name, $label, 'rows="15" cols="80"', $config);
         $this->applyFilter($name, 'trim');
-        $html_type = STUDENT_HTML;
-        if (!empty($_SESSION['status'])) {
-            $html_type = $_SESSION['status'] == COURSEMANAGER ? TEACHER_HTML : STUDENT_HTML;
-        }
-        if (is_array($config)) {
-            if (isset($config['FullPage'])) {
-                $full_page = is_bool($config['FullPage']) ? $config['FullPage'] : ($config['FullPage'] === 'true');
-            } else {
-                $config['FullPage'] = $full_page;
-            }
-        } else {
-            $config = array('FullPage' => (bool) $full_page);
-        }
-        if ($full_page) {
-            $html_type = isset($_SESSION['status']) && $_SESSION['status'] == COURSEMANAGER ? TEACHER_HTML_FULLPAGE : STUDENT_HTML_FULLPAGE;
-            //First *filter* the HTML (markup, indenting, ...)
-            //$this->applyFilter($name,'html_filter_teacher_fullpage');
-        } else {
-            //First *filter* the HTML (markup, indenting, ...)
-            //$this->applyFilter($name,'html_filter_teacher');
-        }
         if ($required) {
             $this->addRule($name, get_lang('ThisFieldIsRequired'), 'required');
         }
-        if ($full_page) {
-            $el = $this->getElement($name);
-            $el->fullPage = true;
+
+        /** @var HTML_QuickForm_html_editor $element */
+        $element = $this->getElement($name);
+
+        if ($element->editor) {
+            $element->editor->processConfig($config);
         }
-        // Add rule to check not-allowed HTML
-        //$this->addRule($name, get_lang('SomeHTMLNotAllowed'), 'html', $html_type);
     }
 
     /**

+ 5 - 9
main/inc/lib/template.lib.php

@@ -1,9 +1,6 @@
 <?php
 /* For licensing terms, see /license.txt */
 
-require_once api_get_path(LIBRARY_PATH).'banner.lib.php';
-require_once api_get_path(SYS_PATH).'vendor/twig/twig/lib/Twig/Autoloader.php';
-
 /**
  * Class Template
  *
@@ -68,9 +65,6 @@ class Template
         $this->hide_global_chat = $hide_global_chat;
         $this->load_plugins     = $load_plugins;
 
-        // Twig settings
-        Twig_Autoloader::register();
-
         $template_paths = array(
             api_get_path(SYS_CODE_PATH).'template', //template folder
             api_get_path(SYS_PLUGIN_PATH) //plugin folder
@@ -437,6 +431,7 @@ class Template
         //Setting app paths/URLs
         $_p = array(
             'web'        => api_get_path(WEB_PATH),
+            'web_relative' => api_get_path(REL_PATH),
             'web_course' => api_get_path(WEB_COURSE_PATH),
             'web_main'   => api_get_path(WEB_CODE_PATH),
             'web_css'    => api_get_path(WEB_CSS_PATH),
@@ -475,13 +470,12 @@ class Template
             $this->theme = $this->preview_theme;
         }
 
-        //Base CSS
+        // Base CSS
         $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'base.css');
 
-        //Default CSS responsive design
+        // Default CSS responsive design
         $css[] = api_get_cdn_path(api_get_path(WEB_CSS_PATH).'bootstrap-responsive.css');
 
-
         //Extra CSS files
         $css[] = api_get_path(WEB_LIBRARY_PATH).'javascript/thickbox.css';
         $css[] = api_get_path(WEB_LIBRARY_PATH).'javascript/chosen/chosen.css';
@@ -582,6 +576,8 @@ class Template
         foreach ($js_files as $js_file) {
             $js_file_to_string .= api_get_js($js_file);
         }
+        // @todo fix this path
+        $js_file_to_string .= '<script type="text/javascript" src="'.api_get_path(WEB_PATH).'vendor/ckeditor/ckeditor/ckeditor.js"></script>';
 
         //Loading email_editor js
         if (!api_is_anonymous() && api_get_setting('allow_email_editor') == 'true') {

+ 7 - 1
main/newscorm/lp_add_item.php

@@ -125,6 +125,12 @@ $(function() {
         window.location.href = $(\'a\', this).attr(\'href\');
     });
 });
+
+$(document).on("ready", function() {
+    CKEDITOR.on("instanceReady", function (e) {
+        showTemplates();
+    });
+});
 </script>';
 
 /* Constants and variables */
@@ -250,7 +256,7 @@ $message = isset($_REQUEST['message']) ? $_REQUEST['message'] : null;
 // Show the template list.
 if ($type == 'document' && !isset($_GET['file'])) {
     // Show the template list.
-    echo '<div id="frmModel" style="display:block; height:890px;width:100px; position:relative;"></div>';
+    echo '<div id="frmModel" class="lp-add-item"></div>';
 }
 
 echo '</div>';

+ 10 - 5
main/newscorm/lp_edit_item.php

@@ -12,7 +12,7 @@
  * @package chamilo.learnpath
 */
 /**
- * INIT SECTION 
+ * INIT SECTION
  */
 
 $this_section = SECTION_COURSES;
@@ -47,6 +47,11 @@ function InnerDialogLoaded() {
     return B.ClickFrame();
 $};'.$_SESSION['oLP']->get_js_dropdown_array().'
 
+$(document).on("ready", function() {
+    CKEDITOR.on("instanceReady", function (e) {
+        showTemplates();
+    });
+});
 </script>';
 
 /* Constants and variables */
@@ -144,15 +149,15 @@ $path_parts = pathinfo($path_file);
 
 if (Database::num_rows($res_doc) > 0 && $path_parts['extension'] == 'html') {
     echo $_SESSION['oLP']->return_new_tree();
-    
+
     // Show the template list
     echo '<p style="border-bottom:1px solid #999999; margin:0; padding:2px;"></p>';
     echo '<br />';
     echo '<div id="frmModel" style="display:block; height:890px;width:100px; position:relative;"></div>';
 } else {
-    echo $_SESSION['oLP']->return_new_tree();    
+    echo $_SESSION['oLP']->return_new_tree();
 }
-        
+
 echo '</div>';
 echo '<div class="span9">';
 
@@ -169,4 +174,4 @@ echo '</div>';
 echo '</div>';
 
 /* FOOTER */
-Display::display_footer();
+Display::display_footer();

+ 21 - 0
main/template/default/javascript/editor/ckeditor/config_js.tpl

@@ -0,0 +1,21 @@
+CKEDITOR.editorConfig = function( config ) {
+    // Define changes to default configuration here.
+    // For complete reference see:
+    // http://docs.ckeditor.com/#!/api/CKEDITOR.config
+
+    // Remove some buttons provided by the standard plugins, which are
+    // not needed in the Standard(s) toolbar.
+    config.removeButtons = 'Underline,Subscript,Superscript';
+
+    // Set the most common block elements.
+    config.format_tags = 'p;h1;h2;h3;pre';
+
+    // Simplify the dialog windows.
+    config.removeDialogTabs = 'image:advanced;link:advanced';
+
+    config.templates_files  = [
+        '{{ _p.web_main ~ 'inc/lib/elfinder/templates.php'}}'
+    ];
+
+    config.customConfig = '{{ _p.web_main ~ 'inc/lib/javascript/ckeditor/config_js.php'}}';
+};

+ 35 - 0
main/template/default/javascript/editor/ckeditor/elfinder.tpl

@@ -0,0 +1,35 @@
+{% extends "default/layout/no_layout.tpl" %}
+
+{% block body %}
+    {% set finderFolder = _p.web ~ 'vendor/barryvdh/elfinder-builds/' %}
+    <!-- elFinder CSS (REQUIRED) -->
+    <link rel="stylesheet" type="text/css" media="screen" href="{{ finderFolder }}css/elfinder.full.css">
+
+    <!-- elFinder JS (REQUIRED) -->
+    <script type="text/javascript" src="{{ finderFolder }}js/elfinder.full.js"></script>
+
+    <!-- elFinder translation (OPTIONAL) -->
+    <script type="text/javascript" src="{{ finderFolder }}js/i18n/elfinder.ru.js"></script>
+
+    <script type="text/javascript" charset="utf-8">
+        // Helper function to get parameters from the query string.
+        function getUrlParam(paramName) {
+            var reParam = new RegExp('(?:[\?&]|&amp;)' + paramName + '=([^&]+)', 'i');
+            var match = window.location.search.match(reParam);
+            return (match && match.length > 1) ? match[1] : '';
+        }
+
+        $().ready(function() {
+            var funcNum = getUrlParam('CKEditorFuncNum');
+            var elf = $('#elfinder').elfinder({
+                url : '{{ _p.web_lib ~ 'elfinder/connectorAction.php' }}',  // connector URL (REQUIRED)
+                getFileCallback : function(file) {
+                    window.opener.CKEDITOR.tools.callFunction(funcNum, file.url);
+                    window.close();
+                },
+                resizable: false
+            }).elfinder('instance');
+        });
+    </script>
+    <div id="elfinder"></div>
+{% endblock %}

+ 6 - 0
main/template/default/javascript/editor/ckeditor/templates.tpl

@@ -0,0 +1,6 @@
+CKEDITOR.addTemplates("default",
+{
+    imagesPath: ' ',
+    templates:
+        {{ templates }}
+});

+ 0 - 4
main/template/default/layout/footer.tpl

@@ -59,7 +59,6 @@
 {# Extra footer configured in admin section, only shown to non-admins #}
 {{ footer_extra_content }}
 
-{% raw %}
 <script>
 
     $("form").on("click", ' .advanced_parameters', function() {
@@ -70,7 +69,6 @@
         });
     });
 
-
     /* Makes row highlighting possible */
     $(document).ready( function() {
         /**
@@ -141,8 +139,6 @@
         };
         $('.boot-tooltip').tooltip(tip_options);
     });
-    {% endraw %}
-
 </script>
 
 {{ execution_stats }}

+ 68 - 4
main/template/default/layout/head.tpl

@@ -15,11 +15,76 @@
 {{ css_file_to_string }}
 {{ css_style_print }}
 {{ js_file_to_string }}
+<script>
+
+// External plugins not part of the default Ckeditor package.
+var plugins = [
+    'oembed',
+    'wordcount',
+    'asciisvg',
+    'video',
+    'toolbarswitch',
+    'audio',
+    'youtube',
+    'leaflet',
+    'asciimath',
+    'glossary',
+    'mapping'
+];
+
+plugins.forEach(function(plugin) {
+    CKEDITOR.plugins.addExternal(plugin, '{{ _p.web_main ~ 'inc/lib/javascript/ckeditor/plugins/' }}' + plugin + '/');
+});
+
+/**
+ * Function use to load templates in a div
+**/
+var showTemplates = function () {
+    CKEDITOR.editorConfig(CKEDITOR.config);
+    CKEDITOR.loadTemplates(CKEDITOR.config.templates_files, function (a){
+        var templatesConfig = CKEDITOR.getTemplates("default");
+
+        var $templatesUL = $("<ul>");
+
+        $.each(templatesConfig.templates, function () {
+            var template = this;
+            var $templateLi = $("<li>");
+
+            var templateHTML = "<img src=\"" + templatesConfig.imagesPath + template.image + "\" ><div>";
+            templateHTML += "<b>" + template.title + "</b>";
+
+            if (template.description) {
+                templateHTML += "<div class=description>" + template.description + "</div>";
+            }
+
+            templateHTML += "</div>";
+
+            $("<a>", {
+                href: "#",
+                html: templateHTML,
+                click: function (e) {
+                    e.preventDefault();
+
+                    CKEDITOR.instances.content.setData(template.html, function () {
+                        this.checkDirty();
+                    });
+                }
+            }).appendTo($templateLi);
+
+            $templatesUL.append($templateLi);
+        });
+
+        $templatesUL.appendTo("#frmModel");
+    });
+};
+
+</script>
 {{ extra_headers }}
 <script>
-//<![CDATA[
+
 // This is a patch for the "__flash__removeCallback" bug, see FS#4378.
-{% raw %}
+/*
+@deprecated seems not to be use.
 if ((navigator.userAgent.toLowerCase().indexOf('msie') != -1 ) && ( navigator.userAgent.toLowerCase().indexOf('opera') == -1 )) {
     window.attachEvent( 'onunload', function() {
         window['__flash__removeCallback'] = function ( instance, name ) {
@@ -32,8 +97,7 @@ if ((navigator.userAgent.toLowerCase().indexOf('msie') != -1 ) && ( navigator.us
         } ;
     });
 }
-{% endraw %}
-//]]>
+*/
 
 function setCheckbox(value, table_id) {
     checkboxes = $("#"+table_id+" input:checkbox");

+ 155 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/CkEditor.php

@@ -0,0 +1,155 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor;
+
+use Chamilo\CoreBundle\Component\Editor\Editor;
+use Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+//use Symfony\Component\Routing\Generator\UrlGenerator;
+
+/**
+ * Class CkEditor
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor
+ */
+class CkEditor extends Editor
+{
+    /**
+     * @return string
+     */
+    public function getEditorTemplate()
+    {
+        return 'javascript/editor/ckeditor/elfinder.tpl';
+    }
+
+    /**
+     * Set js to be include in the template
+     */
+    public function setJavascriptToInclude()
+    {
+        //$jsFolder = api_get_path(WEB_LIBRARY_JS_PATH);
+        //$this->template->addResource($jsFolder.'ckeditor/ckeditor.js', 'js');
+    }
+
+    /**
+     * Return the HTML code required to run editor.
+     *
+     * @return string
+     */
+    public function createHtml()
+    {
+        $html = '<textarea id="'.$this->getName().'" name="'.$this->getName().'" class="ckeditor">
+                 '.$this->value.'
+                 </textarea>';
+        $html .= $this->editorReplace();
+
+        return $html;
+    }
+
+    /**
+     * @return string
+     */
+    public function editorReplace()
+    {
+        $toolbar = new Toolbar\Basic($this->toolbarSet, $this->config, 'CkEditor');
+        $toolbar->setLanguage($this->getLocale());
+        $config = $toolbar->getConfig();
+        $javascript = $this->toJavascript($config);
+        $html = "<script>
+           CKEDITOR.replace('".$this->getName()."',
+               $javascript
+           );
+           </script>";
+
+        return $html;
+    }
+
+    /**
+     * @param array $templates
+     *
+     * @return null
+     */
+    public function formatTemplates($templates)
+    {
+        if (empty($templates)) {
+            return null;
+        }
+        /** @var \Chamilo\CoreBundle\Entity\SystemTemplate $template */
+        $templateList = array();
+
+        $search = array('{CSS}', '{IMG_DIR}', '{REL_PATH}', '{COURSE_DIR}');
+        $replace = array(
+            '',
+            api_get_path(REL_CODE_PATH).'img/',
+            api_get_path(REL_PATH),
+            //api_get_path(REL_DEFAULT_COURSE_DOCUMENT_PATH),
+            //api_get_path(REL_DEFAULT_COURSE_DOCUMENT_PATH)
+        );
+
+        foreach ($templates as $template) {
+            $image = $template->getImage();
+            $image = !empty($image) ? $image : 'empty.gif';
+
+            $image = $this->urlGenerator->generate(
+                'get_document_template_action',
+                array('file' => $image),
+                UrlGenerator::ABSOLUTE_URL
+            );
+
+            $content = str_replace($search, $replace, $template->getContent());
+
+            $templateList[] = array(
+                'title' => $this->translator->trans($template->getTitle()),
+                'description' => $this->translator->trans($template->getComment()),
+                'image' => $image,
+                'html' => $content
+            );
+        }
+
+        return json_encode($templateList);
+    }
+
+    /**
+     * @param array $templates
+     * @return null|string
+     */
+    public function simpleFormatTemplates($templates)
+    {
+        if (empty($templates)) {
+            return null;
+        }
+
+        $search = array('{CSS}', '{IMG_DIR}', '{REL_PATH}', '{COURSE_DIR}');
+        $replace = array(
+            '',
+            api_get_path(REL_CODE_PATH).'img/',
+            api_get_path(REL_PATH),
+            api_get_path(REL_DEFAULT_COURSE_DOCUMENT_PATH),
+            api_get_path(REL_DEFAULT_COURSE_DOCUMENT_PATH)
+        );
+
+        $templateList = array();
+
+        foreach ($templates as $template) {
+            $image = $template['image'];
+            $image = !empty($image) ? $image : 'empty.gif';
+            $image = api_get_path(WEB_PATH).'home/default_platform_document/template_thumb/'.$image;
+
+            /*$image = $this->urlGenerator->generate(
+                'get_document_template_action',
+                array('file' => $image),
+                UrlGenerator::ABSOLUTE_URL
+            );*/
+
+            $content = str_replace($search, $replace, $template['content']);
+
+            $templateList[] = array(
+                'title' => get_lang($template['title']),
+                'description' => get_lang($template['comment']),
+                'image' => $image,
+                'html' => $content
+            );
+        }
+        //var_dump($templateList);
+        return json_encode($templateList);
+    }
+}

+ 106 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Basic.php

@@ -0,0 +1,106 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+
+use Chamilo\CoreBundle\Component\Editor\Toolbar;
+
+/**
+ * Class Basic
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar
+ */
+class Basic extends Toolbar
+{
+    public $defaultPlugins = array('oembed', 'video', 'wordcount', 'templates');
+    public $plugins = array();
+
+    /**
+     * @return array
+     */
+    public function getConfig()
+    {
+        // Original from ckeditor
+        /*
+        $config['toolbarGroups'] = array(
+            array('name' => 'document',  'groups' =>array('mode', 'document', 'doctools')),
+            array('name' => 'clipboard',    'groups' =>array('clipboard', 'undo', )),
+            array('name' => 'editing',    'groups' =>array('clipboard', 'undo', )),
+            array('name' => 'forms',    'groups' =>array('clipboard', 'undo', )),
+            '/',
+            array('name' => 'basicstyles',    'groups' =>array('basicstyles', 'cleanup', )),
+            array('name' => 'paragraph',    'groups' =>array('list', 'indent', 'blocks', 'align' )),
+            array('name' => 'links'),
+            array('name' => 'insert'),
+            '/',
+            array('name' => 'styles'),
+            array('name' => 'colors'),
+            array('name' => 'tools'),
+            array('name' => 'others'),
+            array('name' => 'about')
+        );*/
+
+        $config['toolbarGroups'] = array(
+                 //{ name: 'document',	   groups: [ 'mode', 'document', 'doctools' ] },
+            array('name' => 'document',   'groups' =>array('mode', 'document', 'doctools')),
+            array('name' => 'clipboard',  'groups' =>array('clipboard', 'undo', )),
+            array('name' => 'editing',    'groups' =>array('clipboard', 'undo', )),
+            //array('name' => 'forms',    'groups' =>array('clipboard', 'undo', )),
+            '/',
+            array('name' => 'basicstyles', 'groups' =>array('basicstyles', 'cleanup', )),
+            array('name' => 'paragraph',   'groups' =>array('list', 'indent', 'blocks', 'align')),
+            array('name' => 'links'),
+            array('name' => 'insert'),
+            '/',
+            array('name' => 'styles'),
+            array('name' => 'colors'),
+            array('name' => 'tools'),
+            array('name' => 'others'),
+            array('name' => 'allMedias'),
+            array('name' => 'mode')
+        );
+
+        // file manager (elfinder)
+
+        // http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html
+        $config['filebrowserBrowseUrl'] = api_get_path(WEB_LIBRARY_PATH).'elfinder/filemanager.php';
+
+        $config['customConfig'] = api_get_path(WEB_LIBRARY_PATH).'javascript/ckeditor/config_js.php';
+
+        /*filebrowserFlashBrowseUrl
+        filebrowserFlashUploadUrl
+        filebrowserImageBrowseLinkUrl
+        filebrowserImageBrowseUrl
+        filebrowserImageUploadUrl
+        filebrowserUploadUrl*/
+
+        $config['extraPlugins'] = $this->getPluginsToString();
+
+        //$config['oembed_maxWidth'] = '560';
+        //$config['oembed_maxHeight'] = '315';
+
+        //$config['allowedContent'] = true;
+
+        /*$config['wordcount'] = array(
+            // Whether or not you want to show the Word Count
+            'showWordCount' => true,
+            // Whether or not you want to show the Char Count
+            'showCharCount' => true,
+            // Option to limit the characters in the Editor
+            'charLimit' => 'unlimited',
+            // Option to limit the words in the Editor
+            'wordLimit' => 'unlimited'
+        );*/
+
+        //$config['skins'] = 'moono';
+
+        if (isset($this->config)) {
+            $this->config = array_merge($config, $this->config);
+        } else {
+            $this->config = $config;
+        }
+
+        //$config['width'] = '100';
+        //$config['height'] = '200';
+        return $this->config;
+    }
+}

+ 58 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Documents.php

@@ -0,0 +1,58 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+
+/**
+ * Class Documents
+ *
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar *
+ */
+class Documents extends Basic
+{
+    public $plugins = array(
+        'toolbarswitch',
+        'audio',
+        'video',
+        'youtube',
+        'leaflet',
+        'widget',
+        'lineutils',
+        'mathjax',
+        'asciimath',
+        'glossary',
+        'asciisvg',
+        'mapping'
+    );
+
+    /**
+     * @return mixed
+     */
+    public function getConfig()
+    {
+        $config['toolbarGroups'] = array(
+            array('name' => 'document',  'groups' => array('document', 'doctools')),
+            array('name' => 'clipboard', 'groups' => array('clipboard', 'undo')),
+            array('name' => 'editing',   'groups' => array( 'find', 'selection', 'spellchecker')),
+            //array('name' => 'forms'),
+            '/',
+            array('name' => 'basicstyles', 'groups' => array('basicstyles', 'cleanup')),
+            array('name' => 'paragraph',   'groups' => array('list', 'indent', 'blocks', 'align', 'bidi')),
+            array('name' => 'links'),
+            array('name' => 'insert'),
+            '/',
+            array('name' => 'styles'),
+            array('name' => 'colors'),
+            //array('name' => 'tools'),
+            array('name' => 'others'),
+            array('name' => 'mode')
+        );
+        $config['extraPlugins'] = $this->getPluginsToString();
+        //$config['mathJaxLib'] = $this->urlGenerator->generate('javascript').'/math_jax/MathJax.js?config=default';
+        //$config['mathJaxLib'] = api_get_path(WEB_LIBRARY_JS_PATH).'/math_jax/MathJax.js?config=default';
+        $config['fullPage'] = true;
+
+        return $config;
+    }
+
+}

+ 40 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/IntroductionTool.php

@@ -0,0 +1,40 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+
+/**
+ * Class IntroductionTool
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar
+ */
+class IntroductionTool extends Basic
+{
+    /**
+     * @return mixed
+     */
+    public function getConfig()
+    {
+        $config['toolbarGroups'] = array(
+//            array('name' => 'document',  'groups' =>array('mode', 'document', 'doctools')),
+//            array('name' => 'clipboard',    'groups' =>array('clipboard', 'undo', )),
+            //array('name' => 'editing',    'groups' =>array('clipboard', 'undo', )),
+            //array('name' => 'forms',    'groups' =>array('clipboard', 'undo', )),
+            '/',
+            array('name' => 'basicstyles',    'groups' =>array('basicstyles', 'cleanup', )),
+            array('name' => 'paragraph',    'groups' =>array('list', 'indent', 'blocks', 'align' )),
+            array('name' => 'links'),
+            array('name' => 'insert'),
+            '/',
+            array('name' => 'styles'),
+            array('name' => 'colors'),
+            array('name' => 'tools'),
+            array('name' => 'others'),
+            array('name' => 'mode')
+        );
+
+        $config['fullPage'] = true;
+        //$config['height'] = '200';
+
+        return $config;
+    }
+}

+ 39 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/LearningPathDocuments.php

@@ -0,0 +1,39 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+
+/**
+ * Class LearningPathDocuments
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar
+ */
+class LearningPathDocuments extends Basic
+{
+    /**
+     * @return mixed
+     */
+    public function getConfig()
+    {
+        $config['toolbarGroups'] = array(
+            array('name' => 'document',  'groups' =>array('document', 'doctools')),
+            array('name' => 'clipboard',    'groups' =>array('clipboard', 'undo', )),
+            array('name' => 'editing',    'groups' =>array('clipboard', 'undo', )),
+            array('name' => 'forms',    'groups' =>array('clipboard', 'undo', )),
+            '/',
+            array('name' => 'basicstyles',    'groups' =>array('basicstyles', 'cleanup', )),
+            array('name' => 'paragraph',    'groups' =>array('list', 'indent', 'blocks', 'align' )),
+            array('name' => 'links'),
+            array('name' => 'insert'),
+            '/',
+            array('name' => 'styles'),
+            array('name' => 'colors'),
+            array('name' => 'tools'),
+            array('name' => 'others'),
+            array('name' => 'others')
+        );
+
+        $config['fullPage'] = true;
+
+        return $config;
+    }
+}

+ 35 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Message.php

@@ -0,0 +1,35 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+
+/**
+ * Class Message
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar
+ */
+class Message extends Basic
+{
+    /**
+     * @return mixed
+     */
+    public function getConfig()
+    {
+        $config['toolbarGroups'] = array(
+            '/',
+            array('name' => 'basicstyles',  'groups' =>array('basicstyles', 'cleanup')),
+            array('name' => 'paragraph',    'groups' =>array('list', 'indent', 'blocks', 'align')),
+            array('name' => 'links'),
+            array('name' => 'insert'),
+            '/',
+            array('name' => 'styles'),
+            array('name' => 'colors'),
+            array('name' => 'tools'),
+            array('name' => 'others')
+        );
+
+        $config['fullPage'] = true;
+        //$config['height'] = '200';
+
+        return $config;
+    }
+}

+ 13 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Notebook.php

@@ -0,0 +1,13 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+
+/**
+ * Class Notebook
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar
+ */
+class Notebook extends Basic
+{
+
+}

+ 13 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/NotebookStudent.php

@@ -0,0 +1,13 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+
+/**
+ * Class NotebookStudent
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar
+ */
+class NotebookStudent extends Basic
+{
+
+}

+ 16 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/PortalHomePage.php

@@ -0,0 +1,16 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+
+use Chamilo\CoreBundle\Component\Editor\Toolbar;
+
+/** TrainingDescription
+ * Class PortalHomePage
+ * @todo complete config
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar
+ */
+class PortalHomePage extends Toolbar
+{
+
+}

+ 16 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/PortalNews.php

@@ -0,0 +1,16 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+
+use Chamilo\CoreBundle\Component\Editor\Toolbar;
+
+/**
+ * Class PortalNews
+ * @todo complete config
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar
+ */
+class PortalNews extends Toolbar
+{
+
+}

+ 12 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/ProjectStudent.php

@@ -0,0 +1,12 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+
+/**
+ * Class ProjectStudent
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar
+ */
+class ProjectStudent extends Basic
+{
+}

+ 13 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestAnswerFeedback.php

@@ -0,0 +1,13 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+
+/**
+ * Class TestAnswerFeedback
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar
+ */
+class TestAnswerFeedback extends Basic
+{
+
+}

+ 50 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestFreeAnswer.php

@@ -0,0 +1,50 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+
+/**
+ * Class TestFreeAnswer
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar
+ */
+class TestFreeAnswer extends Basic
+{
+    /**
+     * @return mixed
+     */
+    public function getConfig()
+    {
+        $config['toolbarGroups'] = array(
+            '/',
+            array('name' => 'basicstyles',    'groups' =>array('basicstyles', 'cleanup', )),
+            array('name' => 'paragraph',    'groups' =>array('list', 'indent', 'blocks', 'align' )),
+            array('name' => 'links'),
+            array('name' => 'insert'),
+            '/',
+            array('name' => 'styles'),
+            array('name' => 'colors'),
+            array('name' => 'tools'),
+            array('name' => 'others'),
+            array('name' => 'mode')
+        );
+
+        $config['fullPage'] = false;
+
+        $config['extraPlugins'] = 'wordcount';
+
+        $config['wordcount'] = array(
+            // Whether or not you want to show the Word Count
+            'showWordCount' => true,
+            // Whether or not you want to show the Char Count
+            'showCharCount' => true,
+            // Option to limit the characters in the Editor
+            'charLimit' => 'unlimited',
+            // Option to limit the words in the Editor
+            'wordLimit' => 'unlimited'
+        );
+
+        //$config['height'] = '200';
+
+        return $config;
+    }
+}

+ 54 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestFreeAnswerStrict.php

@@ -0,0 +1,54 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+
+/**
+ * Class TestFreeAnswerStrict
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar
+ */
+class TestFreeAnswerStrict extends Basic
+{
+    /**
+     * @return mixed
+     */
+    public function getConfig()
+    {
+        $config['toolbarGroups'] = array(
+//            array('name' => 'document',  'groups' =>array('mode', 'document', 'doctools')),
+//            array('name' => 'clipboard',    'groups' =>array('clipboard', 'undo', )),
+            //array('name' => 'editing',    'groups' =>array('clipboard', 'undo', )),
+            //array('name' => 'forms',    'groups' =>array('clipboard', 'undo', )),
+            /*'/',
+            array('name' => 'basicstyles',    'groups' =>array('basicstyles', 'cleanup', )),
+            array('name' => 'paragraph',    'groups' =>array('list', 'indent', 'blocks', 'align' )),
+            array('name' => 'links'),
+            array('name' => 'insert'),
+            '/',
+            array('name' => 'styles'),
+            array('name' => 'colors'),
+            array('name' => 'tools'),
+            array('name' => 'others'),
+            array('name' => 'mode')*/
+        );
+
+        $config['fullPage'] = false;
+
+        $config['extraPlugins'] = 'wordcount';
+
+        $config['wordcount'] = array(
+            // Whether or not you want to show the Word Count
+            'showWordCount' => true,
+            // Whether or not you want to show the Char Count
+            'showCharCount' => true,
+            // Option to limit the characters in the Editor
+            'charLimit' => 'unlimited',
+            // Option to limit the words in the Editor
+            'wordLimit' => 'unlimited'
+        );
+
+        $config['removePlugins'] = 'elementspath';
+        //$config['height'] = '200';
+        return $config;
+    }
+}

+ 36 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestProposedAnswer.php

@@ -0,0 +1,36 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+
+/**
+ * Class TestProposedAnswer
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar
+ */
+class TestProposedAnswer
+{
+    /**
+     * @return mixed
+     */
+    public function getConfig()
+    {
+        $config['toolbarGroups'] = array(
+            //array('name' => 'document'),
+            array('name' => 'clipboard',    'groups' =>array('clipboard', 'undo', )),
+            array('name' => 'basicstyles',    'groups' =>array('basicstyles', 'cleanup', )),
+            array('name' => 'paragraph',    'groups' =>array('list', 'indent', 'blocks', 'align' )),
+            array('name' => 'links'),
+            array('name' => 'insert'),
+            '/',
+            array('name' => 'styles'),
+            array('name' => 'colors'),
+            array('name' => 'mode')
+        );
+
+        $config['toolbarCanCollapse'] = true;
+        $config['toolbarStartupExpanded'] = false;
+        //$config['width'] = '100';
+        //$config['height'] = '200';
+        return $config;
+    }
+}

+ 40 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestQuestionDescription.php

@@ -0,0 +1,40 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+
+/**
+ * Class TestQuestionDescription
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar
+ */
+class TestQuestionDescription
+{
+    /**
+     * @return mixed
+     */
+    public function getConfig()
+    {
+        $config['toolbarGroups'] = array(
+            array('name' => 'document',  'groups' =>array('document', 'doctools')),
+            array('name' => 'clipboard',    'groups' =>array('clipboard', 'undo', )),
+            array('name' => 'editing',    'groups' =>array('clipboard', 'undo', )),
+            //array('name' => 'forms',    'groups' =>array('clipboard', 'undo', )),
+            '/',
+            array('name' => 'basicstyles',    'groups' =>array('basicstyles', 'cleanup', )),
+            array('name' => 'paragraph',    'groups' =>array('list', 'indent', 'blocks', 'align' )),
+            array('name' => 'links'),
+            array('name' => 'insert'),
+            '/',
+            array('name' => 'styles'),
+            array('name' => 'colors'),
+            array('name' => 'tools'),
+            array('name' => 'others'),
+            array('name' => 'mode')
+            //array('name' => 'about')
+        );
+
+        //$config['width'] = '100';
+        //$config['height'] = '200';
+        return $config;
+    }
+}

+ 14 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/ToolbarStartExpanded.php

@@ -0,0 +1,14 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+
+use Chamilo\CoreBundle\Component\Editor\Toolbar;
+
+/**
+ * Class ToolbarStartExpanded
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar
+ */
+class ToolbarStartExpanded extends Toolbar
+{
+}

+ 16 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TrainingDescription.php

@@ -0,0 +1,16 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+
+use Chamilo\CoreBundle\Component\Editor\Toolbar;
+
+/**
+ * Class TrainingDescription
+ * @todo complete config
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar
+ */
+class TrainingDescription extends Toolbar
+{
+
+}

+ 36 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/UniqueAnswerImage.php

@@ -0,0 +1,36 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+
+/**
+ * Class UniqueAnswerImage
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar
+ */
+class UniqueAnswerImage extends Basic
+{
+    /**
+     * @return mixed
+     */
+    public function getConfig()
+    {
+        $config['toolbarGroups'] = array(
+            '/',
+            array('name' => 'basicstyles',    'groups' =>array('basicstyles', 'cleanup', )),
+            array('name' => 'paragraph',    'groups' =>array('list', 'indent', 'blocks', 'align' )),
+            array('name' => 'links'),
+            array('name' => 'insert'),
+            '/',
+            array('name' => 'styles'),
+            array('name' => 'colors'),
+            array('name' => 'tools'),
+            array('name' => 'others'),
+            array('name' => 'mode')
+        );
+
+        $config['fullPage'] = true;
+        //$config['height'] = '200';
+
+        return $config;
+    }
+}

+ 13 - 0
src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/WikiStudent.php

@@ -0,0 +1,13 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar;
+
+/**
+ * Class WikiStudent
+ * @package Chamilo\CoreBundle\Component\Editor\CkEditor\Toolbar
+ */
+class WikiStudent extends Basic
+{
+
+}

+ 397 - 0
src/Chamilo/CoreBundle/Component/Editor/Connector.php

@@ -0,0 +1,397 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor;
+
+use Doctrine\ORM\EntityManager;
+use Chamilo\UserBundle\Entity\User;
+use Chamilo\CoreBundle\Entity\Course;
+
+use Symfony\Component\Translation\Translator;
+use Symfony\Component\Routing\Router;
+use Chamilo\CoreBundle\Component\Editor\Driver\Driver;
+//use Symfony\Component\Security\Core\SecurityContext;
+
+/**
+ * Class elFinder Connector - editor + Chamilo repository
+ * @package Chamilo\CoreBundle\Component\Editor
+ */
+class Connector
+{
+    /** @var Course */
+    public $course;
+
+    /** @var User */
+    public $user;
+
+    /** @var Translator */
+    public $translator;
+
+    /** @var Router */
+    public $urlGenerator;
+    /** @var SecurityContext */
+    public $security;
+
+    public $paths;
+
+    public $entityManager;
+
+    public $drivers = array();
+    public $driverList = array();
+
+    public function __construct(
+        /*EntityManager $entityManager,
+        array $paths,
+        Router $urlGenerator,
+        Translator $translator,
+        SecurityContext $security,*/
+        //$user,
+        //$course = null
+    ) {
+        $this->paths = array(
+            'root_sys' => api_get_path(SYS_PATH),
+            'sys_root' => api_get_path(SYS_PATH), // just an alias
+            'sys_data_path' => api_get_path(SYS_COURSE_PATH),
+         //   'sys_config_path' => $app['path.config'],
+            'path.temp' => api_get_path(SYS_ARCHIVE_PATH),
+            //'sys_log_path' => $app['path.logs']
+        );
+        /*$this->entityManager = $entityManager;
+        $this->paths = $paths;
+        $this->urlGenerator = $urlGenerator;
+        $this->translator = $translator;
+        $this->security = $security;*/
+        $this->user = api_get_user_info();
+        $this->course = api_get_course_info();
+        $this->driverList = $this->getDefaultDriverList();
+    }
+
+    /**
+     * @return array
+     */
+    public function getDriverList()
+    {
+        return $this->driverList;
+    }
+
+    /**
+     * Available driver list.
+     * @param array
+     */
+    public function setDriverList($list)
+    {
+        $this->driverList = $list;
+    }
+
+    /**
+     * Available driver list.
+     * @return array
+     */
+    private function getDefaultDriverList()
+    {
+        return array(
+            'CourseDriver',
+            'CourseUserDriver',
+            'DropBoxDriver',
+            'HomeDriver',
+            'PersonalDriver'
+        );
+    }
+
+    /**
+     * @param Driver $driver
+     */
+    public function addDriver($driver)
+    {
+        if (!empty($driver)) {
+            $this->drivers[$driver->getName()] = $driver;
+        }
+    }
+
+    /**
+     * @return array
+     */
+    public function getDrivers()
+    {
+        return $this->drivers;
+    }
+
+    /**
+     * @param string $driverName
+     * @return Driver $driver
+     */
+    public function getDriver($driverName)
+    {
+        if (isset($this->drivers[$driverName])) {
+            return $this->drivers[$driverName];
+        }
+
+        return null;
+    }
+
+    /**
+     * @param bool $processDefaultValues
+     * @return array
+     */
+    public function getRoots($processDefaultValues = true)
+    {
+        $roots = array();
+        /** @var Driver $driver */
+        $drivers = $this->getDrivers();
+
+        foreach ($drivers as $driver) {
+            if ($processDefaultValues) {
+                $plugin = array(
+                    'chamilo' => array(
+                        'driverName' => $driver->getName(),
+                        'connector' => $this,
+                    )
+                );
+                $configuration = $driver->getConfiguration();
+                $configuration['plugin'] = $plugin;
+                $root = $this->updateWithDefaultValues($configuration);
+            }
+            $roots[] = $root;
+        }
+
+        return $roots;
+    }
+
+    /**
+     * Merges the default driver settings.
+     * @param array $driver
+     * @return array
+     */
+    public function updateWithDefaultValues($driver)
+    {
+        if (empty($driver) || !isset($driver['driver'])) {
+            return array();
+        }
+
+        $defaultDriver = $this->getDefaultDriverSettings();
+
+        if (isset($driver['attributes'])) {
+            $attributes = array_merge($defaultDriver['attributes'], $driver['attributes']);
+        } else {
+            $attributes = $defaultDriver['attributes'];
+        }
+
+        $driverUpdated = array_merge($defaultDriver, $driver);
+        $driverUpdated['driver'] = 'Chamilo\CoreBundle\Component\Editor\Driver\\'.$driver['driver'];
+        $driverUpdated['attributes'] = $attributes;
+
+        return $driverUpdated;
+    }
+
+    /**
+     * Get default driver settings.
+     * @return array
+     */
+    private function getDefaultDriverSettings()
+    {
+        // for more options: https://github.com/Studio-42/elFinder/wiki/Connector-configuration-options
+        return array(
+            'uploadOverwrite' => false, // Replace files on upload or give them new name if the same file was uploaded
+            //'acceptedName' =>
+            'uploadAllow' => array(
+                'image',
+                'audio',
+                'video',
+                'text/html',
+                'text/csv',
+                'application/pdf',
+                'application/postscript',
+                'application/vnd.ms-word',
+                'application/vnd.ms-excel',
+                'application/vnd.ms-powerpoint',
+                'application/pdf',
+                'application/xml',
+                'application/vnd.oasis.opendocument.text',
+                'application/x-shockwave-flash'
+            ), # allow files
+            //'uploadDeny' => array('text/x-php'),
+            'uploadOrder' => array('allow'), // only executes allow
+            'disabled' => array(
+                'duplicate',
+                'rename',
+                'mkdir',
+                'mkfile',
+                'copy',
+                'cut',
+                'paste',
+                'edit',
+                'extract',
+                'archive',
+                'help',
+                'resize'
+            ),
+            'attributes' =>  array(
+                // Hiding dangerous files
+                array(
+                    'pattern' => '/\.(php|py|pl|sh|xml)$/i',
+                    'read' => false,
+                    'write' => false,
+                    'hidden' => true,
+                    'locked' => false
+                ),
+                // Hiding _DELETED_ files
+                array(
+                    'pattern' => '/_DELETED_/',
+                    'read' => false,
+                    'write' => false,
+                    'hidden' => true,
+                    'locked' => false
+                ),
+                // Hiding thumbnails
+                array(
+                    'pattern' => '/.tmb/',
+                    'read' => false,
+                    'write' => false,
+                    'hidden' => true,
+                    'locked' => false
+                ),
+                array(
+                    'pattern' => '/.thumbs/',
+                    'read' => false,
+                    'write' => false,
+                    'hidden' => true,
+                    'locked' => false
+                ),
+                array(
+                    'pattern' => '/.quarantine/',
+                    'read' => false,
+                    'write' => false,
+                    'hidden' => true,
+                    'locked' => false
+                )
+            )
+        );
+    }
+
+    /**
+     * @return array
+     */
+    public function getOperations()
+    {
+        //https://github.com/Studio-42/elFinder/wiki/Connector-configuration-options-2.1
+        $opts = array(
+            //'debug' => true,
+            'bind' => array(
+                'upload rm' => array($this, 'manageCommands')
+            )
+        );
+
+        $this->setDrivers();
+
+        $opts['roots'] = $this->getRoots();
+
+        return $opts;
+    }
+
+    /**
+     * Set drivers from list
+     */
+    public function setDrivers()
+    {
+        foreach ($this->getDriverList() as $driverName) {
+            $this->setDriver($driverName);
+        }
+    }
+
+    /**
+     * Sets a driver.
+     * @param string $driverName
+     */
+    public function setDriver($driverName)
+    {
+        $driverClass = $this->getDriverClass($driverName);
+
+        /** @var Driver $driver */
+        $driver = new $driverClass();
+        $driver->setName($driverName);
+        $driver->setConnector($this);
+        $this->addDriver($driver);
+    }
+
+    /**
+     * Simple function to demonstrate how to control file access using "accessControl" callback.
+     * This method will disable accessing files/folders starting from  '.' (dot)
+     *
+     * @param string $attr  attribute name (read|write|locked|hidden)
+     * @param string $path  file path relative to volume root directory started with directory separator
+     * @param string $data
+     * @param string $volume
+     * @return bool|null
+     **/
+    public function access($attr, $path, $data, $volume)
+    {
+    	return strpos(basename($path), '.') === 0       // if file/folder begins with '.' (dot)
+    		? !($attr == 'read' || $attr == 'write')    // set read+write to false, other (locked+hidden) set to true
+    		:  null;                                    // else elFinder decide it itself
+    }
+
+    /**
+     * @param string $cmd
+     * @param array $result
+     * @param array $args
+     * @param Finder $elFinder
+     */
+    public function manageCommands($cmd, $result, $args, $elFinder)
+    {
+        $cmd = ucfirst($cmd);
+        $cmd = 'after'.$cmd;
+/*
+        if (isset($args['target'])) {
+            $driverName = $elFinder->getVolumeDriverNameByTarget($args['target']);
+        }
+
+        if (isset($args['targets'])) {
+            foreach ($args['targets'] as $target) {
+                $driverName = $elFinder->getVolumeDriverNameByTarget($target);
+                break;
+            }
+        }
+*/
+        if (empty($driverName)) {
+            return false;
+        }
+
+        if (!empty($result['error'])) {
+        }
+
+        if (!empty($result['warning'])) {
+        }
+
+        if (!empty($result['removed'])) {
+            foreach ($result['removed'] as $file) {
+                /** @var Driver $driver */
+//                $driver = $this->getDriver($driverName);
+//                $driver->$cmd($file, $args, $elFinder);
+                // removed file contain additional field "realpath"
+                //$log .= "\tREMOVED: ".$file['realpath']."\n";
+            }
+        }
+
+        if (!empty($result['added'])) {
+            foreach ($result['added'] as $file) {
+//                $driver = $this->getDriver($driverName);
+//                $driver->$cmd($file, $args, $elFinder);
+            }
+        }
+
+        if (!empty($result['changed'])) {
+            foreach ($result['changed'] as $file) {
+                //$log .= "\tCHANGED: ".$elfinder->realpath($file['hash'])."\n";
+            }
+        }
+    }
+
+    /**
+     * @param string $driver
+     * @return string
+     */
+    private function getDriverClass($driver)
+    {
+        return 'Chamilo\CoreBundle\Component\Editor\Driver\\'.$driver;
+    }
+}

+ 163 - 0
src/Chamilo/CoreBundle/Component/Editor/Driver/CourseDriver.php

@@ -0,0 +1,163 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\Driver;
+
+/**
+ * Class CourseDriver
+ * @package Chamilo\CoreBundle\Component\Editor\Driver
+ *
+ */
+class CourseDriver extends Driver
+{
+    public $name = 'CourseDriver';
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getConfiguration()
+    {
+        if (!empty($this->connector->course)) {
+            //$translator = $this->connector->translator;
+            //$code = $this->connector->course->getCode();
+            $courseCode = $this->connector->course['code'];
+            $alias = $courseCode.' '.get_lang('Documents');
+
+            return array(
+                'driver' => 'CourseDriver',
+                'path' => $this->getCourseDocumentSysPath(),
+                'URL' => $this->getCourseDocumentRelativeWebPath(),
+                'accessControl' => array($this, 'access'),
+                'alias' => $alias,
+                'attributes' => array(
+                    // Hide shared_folder
+                    array(
+                        'pattern' => '/shared_folder/',
+                        'read' => false,
+                        'write' => false,
+                        'hidden' => true,
+                        'locked' => false
+                    ),
+                )
+            );
+        }
+    }
+
+    /**
+     * This is the absolute document course path like
+     * /var/www/portal/data/courses/XXX/document/
+     * @return string
+     */
+    public function getCourseDocumentSysPath()
+    {
+        $url = null;
+        if (isset($this->connector->course)) {
+            //$directory = $this->connector->course->getDirectory();
+            $directory = $this->connector->course['directory'];
+            $dataPath = $this->connector->paths['sys_data_path'];
+            $url = $dataPath.$directory.'/document/';
+        }
+
+        return $url;
+    }
+
+    /**
+     * @return string
+     */
+    public function getCourseDocumentRelativeWebPath()
+    {
+        $url = null;
+        if (isset($this->connector->course)) {
+            $directory = $this->connector->course['directory'];
+            $url = api_get_path(REL_COURSE_PATH).$directory.'/document/';
+        }
+
+        return $url;
+    }
+
+
+    /**
+     * @return string
+     */
+    public function getCourseDocumentWebPath()
+    {
+        $url = null;
+        if (isset($this->connector->course)) {
+            $directory = $this->connector->course->getDirectory();
+            $url = api_get_path(WEB_COURSE_PATH).$directory.'/document/';
+        }
+
+        return $url;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function upload($fp, $dst, $name, $tmpname)
+    {
+        $this->setConnectorFromPlugin();
+
+        // upload file by elfinder.
+        $result = parent::upload($fp, $dst, $name, $tmpname);
+
+        $name = $result['name'];
+        $filtered = \URLify::filter($result['name'], 80);
+
+        if (strcmp($name, $filtered) != 0) {
+            /*$arg = array('target' => $file['hash'], 'name' => $filtered);
+            $elFinder->exec('rename', $arg);*/
+            $this->rename($result['hash'], $filtered);
+        }
+
+        $realPath = $this->realpath($result['hash']);
+
+        if (!empty($realPath)) {
+            // Getting file info
+            //$info = $elFinder->exec('file', array('target' => $file['hash']));
+            /** @var elFinderVolumeLocalFileSystem $volume */
+            //$volume = $info['volume'];
+            //$root = $volume->root();
+            //var/www/chamilogits/data/courses/NEWONE/document
+            $realPathRoot = $this->getCourseDocumentSysPath();
+
+            // Removing course path
+            $realPath = str_replace($realPathRoot, '/', $realPath);
+            add_document(
+                $this->connector->course,
+                $realPath,
+                'file',
+                intval($result['size']),
+                $result['name']
+            );
+        }
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function rm($hash)
+    {
+        // elfinder does not delete the file
+        //parent::rm($hash);
+        $this->setConnectorFromPlugin();
+
+        $path = $this->decode($hash);
+        $stat = $this->stat($path);
+        $stat['realpath'] = $path;
+        $this->removed[] = $stat;
+
+        $realFilePath = $path;
+        $coursePath = $this->getCourseDocumentSysPath();
+        $filePath = str_replace($coursePath, '/', $realFilePath);
+
+        \DocumentManager::delete_document(
+            $this->connector->course,
+            $filePath,
+            $coursePath
+        );
+
+        return true;
+    }
+}

+ 37 - 0
src/Chamilo/CoreBundle/Component/Editor/Driver/CourseUserDriver.php

@@ -0,0 +1,37 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\Driver;
+
+/**
+ * Class CourseUserDriver
+ * @package Chamilo\CoreBundle\Component\Editor\Driver
+ */
+class CourseUserDriver extends CourseDriver
+{
+    public $name = 'CourseUserDriver';
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getConfiguration()
+    {
+        if (!empty($this->connector->course)) {
+            $userId = api_get_user_id();
+            $path = 'shared_folder/sf_user_'.$userId;
+
+            $alias = $this->connector->course['code'].' '.get_lang('CourseUserDocument');
+
+            if (!empty($userId)) {
+                return array(
+                    'driver' => 'CourseUserDriver',
+                    'alias' => $alias,
+                    'path' => $this->getCourseDocumentSysPath().$path,
+                    //'alias' => $courseInfo['code'].' personal documents',
+                    'URL' => $this->getCourseDocumentRelativeWebPath().$path,
+                    'accessControl' => 'access'
+                );
+            }
+        }
+    }
+}

+ 63 - 0
src/Chamilo/CoreBundle/Component/Editor/Driver/Driver.php

@@ -0,0 +1,63 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\Driver;
+
+use Chamilo\CoreBundle\Component\Editor\Connector;
+
+/**
+ * Class Driver
+ * @package Chamilo\CoreBundle\Component\Editor\Driver
+ */
+class Driver extends \elFinderVolumeLocalFileSystem implements DriverInterface
+{
+    /** @var string */
+    public $name;
+
+    /** @var Connector */
+    public $connector;
+
+    /**
+     * Gets driver name.
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * Gets driver name.
+     * @param string
+     */
+    public function setName($name)
+    {
+        $this->name = $name;
+    }
+
+    /**
+     * Set connector
+     * @param Connector $connector
+     */
+    public function setConnector(Connector $connector)
+    {
+        $this->connector = $connector;
+    }
+
+    /**
+     * @return array
+     */
+    public function getAppPluginOptions()
+    {
+        return $this->getOptionsPlugin('chamilo');
+    }
+
+    /**
+     * @return Connector
+     */
+    public function setConnectorFromPlugin()
+    {
+        $options = $this->getAppPluginOptions();
+        $this->setConnector($options['connector']);
+    }
+}

+ 41 - 0
src/Chamilo/CoreBundle/Component/Editor/Driver/DriverInterface.php

@@ -0,0 +1,41 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\Driver;
+
+use Chamilo\CoreBundle\Component\Editor\Connector;
+
+/**
+ * Class DriverInterface
+ * @package Chamilo\CoreBundle\Component\Editor\Driver
+ */
+interface DriverInterface
+{
+    /**
+     * Gets driver name.
+     * @return string
+     */
+    public function getName();
+
+    /**
+     * Gets driver name.
+     * @param string
+     */
+    public function setName($name);
+
+    /**
+     * Set connector
+     * @param Connector $connector
+     */
+    public function setConnector(Connector $connector);
+
+    /**
+     * @return array
+     */
+    public function getAppPluginOptions();
+
+    /**
+     * @return Connector
+     */
+    public function setConnectorFromPlugin();
+}

+ 641 - 0
src/Chamilo/CoreBundle/Component/Editor/Driver/DropBoxDriver.php

@@ -0,0 +1,641 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\Driver;
+
+use Chamilo\CoreBundle\Entity\CDropboxFile;
+use Chamilo\CoreBundle\Component\Editor\Connector;
+
+/**
+ * Class DropBoxDriver
+ * @package Chamilo\CoreBundle\Component\Editor\Driver
+ */
+class DropBoxDriver extends \elFinderVolumeMySQL implements DriverInterface
+{
+    /** @var string */
+    public $name = 'DropBoxDriver';
+
+    /** @var Connector */
+    public $connector;
+
+    /**
+     * Gets driver name.
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * Gets driver name.
+     * @param string
+     */
+    public function setName($name)
+    {
+        $this->name = $name;
+    }
+
+    /**
+     * Set connector
+     * @param Connector $connector
+     */
+    public function setConnector(Connector $connector)
+    {
+        $this->connector = $connector;
+    }
+
+    /**
+     * @return array
+     */
+    public function getAppPluginOptions()
+    {
+        return $this->getOptionsPlugin('chamilo');
+    }
+
+    /**
+     * @return Connector
+     */
+    public function setConnectorFromPlugin()
+    {
+        $options = $this->getAppPluginOptions();
+        $this->setConnector($options['connector']);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getConfiguration()
+    {
+        if ($this->connector->security->isGranted('IS_AUTHENTICATED_FULLY')) {
+
+            /** @var \Chamilo\CoreBundle\Entity\Repository\UserRepository $repository */
+            /*$repository = $this->connector->entityManager->getRepository('Chamilo\UserBundle\Entity\User');
+            $courses = $repository->getCourses($this->connector->user);*/
+
+            //if (!empty($courses)) {
+                $userId = $this->connector->user->getUserId();
+                if (!empty($userId)) {
+                    return array(
+                        'driver'     => 'DropBoxDriver',
+                        'path'       => '1',
+                        'alias' => 'dropbox',
+                        'tmpPath' => $this->connector->paths['path.temp'],
+                        //'alias' => $courseInfo['code'].' personal documents',
+                        //'URL' => $this->getCourseDocumentRelativeWebPath().$path,
+                        'accessControl' => 'access'
+                    );
+                }
+            //}
+        }
+    }
+
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    protected function init()
+    {
+        $this->updateCache($this->options['path'], $this->_stat($this->options['path']));
+        return true;
+    }
+
+    /**
+     * Set tmp path
+     *
+     * @return void
+     * @author Dmitry (dio) Levashov
+     **/
+    protected function configure() {
+        parent::configure();
+
+        if (($tmp = $this->options['tmpPath'])) {
+            if (!file_exists($tmp)) {
+                if (@mkdir($tmp)) {
+                    @chmod($tmp, $this->options['tmbPathMode']);
+                }
+            }
+
+            $this->tmpPath = is_dir($tmp) && is_writable($tmp) ? $tmp : false;
+        }
+
+        if (!$this->tmpPath && $this->tmbPath && $this->tmbPathWritable) {
+            $this->tmpPath = $this->tmbPath;
+        }
+
+        $this->mimeDetect = 'internal';
+    }
+
+
+
+    /**
+     * Close connection
+     *
+     * @return void
+     * @author Dmitry (dio) Levashov
+     **/
+    public function umount() {
+        return true;
+    }
+
+
+    /* FS API */
+
+    /**
+     * Cache dir contents
+     *
+     * @param  string  $path  dir path
+     * @return void
+     * @author Dmitry Levashov
+     **/
+    protected function cacheDir($path)
+    {
+        $this->setConnectorFromPlugin();
+        $posts = $this->connector->user->getDropBoxReceivedFiles();
+        $this->dirsCache[$path] = array();
+
+        if (!empty($posts)) {
+            foreach ($posts as $post) {
+                /** @var CDropboxFile $file */
+                $file = $post->getFile();
+
+                $data = $this->transformFileInStat($file);
+                $id = $data['id'];
+                if (($stat = $this->updateCache($id, $data)) && empty($stat['hidden'])) {
+                    $this->dirsCache[$path][] = $id;
+                }
+            }
+            return $this->dirsCache[$path];
+        }
+        return $this->dirsCache[$path];
+    }
+
+    /***************** file stat ********************/
+    /**
+     * Return stat for given path.
+     * Stat contains following fields:
+     * - (int)    size    file size in b. required
+     * - (int)    ts      file modification time in unix time. required
+     * - (string) mime    mimetype. required for folders, others - optionally
+     * - (bool)   read    read permissions. required
+     * - (bool)   write   write permissions. required
+     * - (bool)   locked  is object locked. optionally
+     * - (bool)   hidden  is object hidden. optionally
+     * - (string) alias   for symlinks - link target path relative to root path. optionally
+     * - (string) target  for symlinks - link target path. optionally
+     *
+     * If file does not exists - returns empty array or false.
+     *
+     * @param  string  $path    file path
+     * @return array|false
+     * @author Dmitry (dio) Levashov
+     **/
+    protected function _stat($path)
+    {
+        $this->setConnectorFromPlugin();
+
+        $userId = $this->connector->user->getUserId();
+        $criteria = array();
+        $criteria['uploaderId'] = $userId;
+
+        if ($path != 1) {
+            $criteria['filename'] = $path;
+            $criteria = array('filename' => $path);
+        } else {
+            return $this->returnDirectory();
+        }
+
+        $file = $this->connector->entityManager->getRepository('Chamilo\CoreBundle\Entity\CDropboxFile')->findOneBy($criteria);
+
+        if ($file) {
+            $stat = $this->transformFileInStat($file);
+            return $stat;
+        }
+        return array();
+    }
+
+    /**
+     * @return array
+     */
+    private function returnDirectory()
+    {
+        return array(
+            //'id' => $file->getId().$file->getCId(),
+            'name' => 'Dropbox',
+            //'ts' => $file->getUploadDate(),
+            'mime' => 'directory',
+            'read' => true,
+            'write' => true,
+            'locked' => false,
+            'hidden' => false,
+            'dirs' => 0
+        );
+    }
+
+    /**
+     * @param CDropboxFile $file
+     * @return array
+     */
+    private function transformFileInStat(CDropboxFile $file)
+    {
+        $stat = array(
+            'id' => $file->getId().$file->getCId(),
+            'name' => $file->getFilename(),
+            'ts' => $file->getUploadDate(),
+            'mime' => 'directory',
+            'read' => true,
+            'write' => false,
+            'locked' => false,
+            'hidden' => false,
+            'width' => 100,
+            'height' => 100,
+            'dirs' => 0
+        );
+        return $stat;
+
+        /*
+        if ($stat['parent_id']) {
+            $stat['phash'] = $this->encode($stat['parent_id']);
+        }
+        if ($stat['mime'] == 'directory') {
+            unset($stat['width']);
+            unset($stat['height']);
+        } else {
+            unset($stat['dirs']);
+        }
+        unset($stat['id']);
+        unset($stat['parent_id']);
+        */
+    }
+
+    /**
+     * Return array of parents paths (ids)
+     *
+     * @param  int   $path  file path (id)
+     * @return array
+     * @author Dmitry (dio) Levashov
+     **/
+    protected function getParents($path) {
+        $parents = array();
+
+        while ($path) {
+            if ($file = $this->stat($path)) {
+                array_unshift($parents, $path);
+                $path = isset($file['phash']) ? $this->decode($file['phash']) : false;
+            }
+        }
+
+        if (count($parents)) {
+            array_pop($parents);
+        }
+        return $parents;
+    }
+
+    /**
+     * Return correct file path for LOAD_FILE method
+     *
+     * @param  string $path  file path (id)
+     * @return string
+     * @author Troex Nevelin
+     **/
+    protected function loadFilePath($path) {
+        $realPath = realpath($path);
+        if (DIRECTORY_SEPARATOR == '\\') { // windows
+            $realPath = str_replace('\\', '\\\\', $realPath);
+        }
+        return $this->db->real_escape_string($realPath);
+    }
+
+    /**
+     * Recursive files search
+     *
+     * @param  string  $path   dir path
+     * @param  string  $q      search string
+     * @param  array   $mimes
+     * @return array
+     * @author Dmitry (dio) Levashov
+     **/
+    protected function doSearch($path, $q, $mimes) {
+        return array();
+    }
+
+
+    /*********************** paths/urls *************************/
+
+    /**
+     * Return parent directory path
+     *
+     * @param  string  $path  file path
+     * @return string
+     * @author Dmitry (dio) Levashov
+     **/
+    protected function _dirname($path) {
+        return ($stat = $this->stat($path)) ? ($stat['phash'] ? $this->decode($stat['phash']) : $this->root) : false;
+    }
+
+    /**
+     * Return file name
+     *
+     * @param  string  $path  file path
+     * @return string
+     * @author Dmitry (dio) Levashov
+     **/
+    protected function _basename($path) {
+        return ($stat = $this->stat($path)) ? $stat['name'] : false;
+    }
+
+
+    /**
+     * Return normalized path, this works the same as os.path.normpath() in Python
+     *
+     * @param  string  $path  path
+     * @return string
+     * @author Troex Nevelin
+     **/
+    protected function _normpath($path) {
+        return $path;
+    }
+
+    /**
+     * Return file path related to root dir
+     *
+     * @param  string  $path  file path
+     * @return string
+     * @author Dmitry (dio) Levashov
+     **/
+    protected function _relpath($path) {
+        return $path;
+    }
+
+    /**
+     * Convert path related to root dir into real path
+     *
+     * @param  string  $path  file path
+     * @return string
+     * @author Dmitry (dio) Levashov
+     **/
+    protected function _abspath($path) {
+        return $path;
+    }
+
+    /**
+     * Return fake path started from root dir
+     *
+     * @param  string  $path  file path
+     * @return string
+     * @author Dmitry (dio) Levashov
+     **/
+    protected function _path($path) {
+        if (($file = $this->stat($path)) == false) {
+            return '';
+        }
+
+        $parentsIds = $this->getParents($path);
+        $path = '';
+        foreach ($parentsIds as $id) {
+            $dir = $this->stat($id);
+            $path .= $dir['name'].$this->separator;
+        }
+        return $path.$file['name'];
+    }
+
+    /**
+     * Return true if $path is children of $parent
+     *
+     * @param  string  $path    path to check
+     * @param  string  $parent  parent path
+     * @return bool
+     * @author Dmitry (dio) Levashov
+     **/
+    protected function _inpath($path, $parent) {
+        return $path == $parent
+            ? true
+            : in_array($parent, $this->getParents($path));
+    }
+
+
+
+    /**
+     * Return true if path is dir and has at least one childs directory
+     *
+     * @param  string  $path  dir path
+     * @return bool
+     * @author Dmitry (dio) Levashov
+     **/
+    protected function _subdirs($path) {
+        return ($stat = $this->stat($path)) && isset($stat['dirs']) ? $stat['dirs'] : false;
+    }
+
+    /**
+     * Return object width and height
+     * Usualy used for images, but can be realize for video etc...
+     *
+     * @param  string  $path  file path
+     * @param  string  $mime  file mime type
+     * @return string
+     * @author Dmitry (dio) Levashov
+     **/
+    protected function _dimensions($path, $mime) {
+        return ($stat = $this->stat($path)) && isset($stat['width']) && isset($stat['height']) ? $stat['width'].'x'.$stat['height'] : '';
+    }
+
+    /******************** file/dir content *********************/
+
+    /**
+     * Return files list in directory.
+     *
+     * @param  string  $path  dir path
+     * @return array
+     * @author Dmitry (dio) Levashov
+     **/
+    protected function _scandir($path) {
+        return isset($this->dirsCache[$path])
+            ? $this->dirsCache[$path]
+            : $this->cacheDir($path);
+    }
+
+    /**
+     * Open file and return file pointer
+     *
+     * @param  string  $path  file path
+     * @param  string  $mode  open file mode (ignored in this driver)
+     * @return resource|false
+     * @author Dmitry (dio) Levashov
+     **/
+    protected function _fopen($path, $mode='rb') {
+        $fp = $this->tmbPath
+            ? @fopen($this->tmpname($path), 'w+')
+            : @tmpfile();
+
+
+        if ($fp) {
+            if (($res = $this->query('SELECT content FROM '.$this->tbf.' WHERE id="'.$path.'"'))
+                && ($r = $res->fetch_assoc())) {
+                fwrite($fp, $r['content']);
+                rewind($fp);
+                return $fp;
+            } else {
+                $this->_fclose($fp, $path);
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Close opened file
+     *
+     * @param  resource  $fp  file pointer
+     * @return bool
+     * @author Dmitry (dio) Levashov
+     **/
+    protected function _fclose($fp, $path='') {
+        @fclose($fp);
+        if ($path) {
+            @unlink($this->tmpname($path));
+        }
+    }
+
+    /********************  file/dir manipulations *************************/
+
+    /**
+     * Create dir and return created dir path or false on failed
+     *
+     * @param  string  $path  parent dir path
+     * @param string  $name  new directory name
+     * @return string|bool
+     * @author Dmitry (dio) Levashov
+     **/
+    protected function _mkdir($path, $name) {
+        return $this->make($path, $name, 'directory') ? $this->_joinPath($path, $name) : false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function _mkfile($path, $name) {
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function _symlink($target, $path, $name) {
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function _copy($source, $targetDir, $name) {
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function _move($source, $targetDir, $name) {
+        return false;
+    }
+
+    /**
+     * Remove file
+     *
+     * @param  string  $path  file path
+     * @return bool
+     * @author Dmitry (dio) Levashov
+     **/
+    protected function _unlink($path) {
+        return false;
+        return $this->query(sprintf('DELETE FROM %s WHERE id=%d AND mime!="directory" LIMIT 1', $this->tbf, $path)) && $this->db->affected_rows;
+    }
+
+    /**
+     * Remove dir
+     *
+     * @param  string  $path  dir path
+     * @return bool
+     * @author Dmitry (dio) Levashov
+     **/
+    protected function _rmdir($path) {
+        return false;
+        return $this->query(sprintf('DELETE FROM %s WHERE id=%d AND mime="directory" LIMIT 1', $this->tbf, $path)) && $this->db->affected_rows;
+    }
+
+    /**
+     * undocumented function
+     *
+     * @return void
+     * @author Dmitry Levashov
+     **/
+    protected function _setContent($path, $fp) {
+        rewind($fp);
+        $fstat = fstat($fp);
+        $size = $fstat['size'];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function _save($fp, $dir, $name, $stat) {
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function _getContents($path) {
+        return false;
+        //return ($res = $this->query(sprintf('SELECT content FROM %s WHERE id=%d', $this->tbf, $path))) && ($r = $res->fetch_assoc()) ? $r['content'] : false;
+    }
+
+    /**
+     * Write a string to a file
+     *
+     * @param  string  $path     file path
+     * @param  string  $content  new file content
+     * @return bool
+     * @author Dmitry (dio) Levashov
+     **/
+    protected function _filePutContents($path, $content) {
+        return false;
+        //return $this->query(sprintf('UPDATE %s SET content="%s", size=%d, mtime=%d WHERE id=%d LIMIT 1', $this->tbf, $this->db->real_escape_string($content), strlen($content), time(), $path));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function _checkArchivers() {
+        return;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function _unpack($path, $arc) {
+        return;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function _findSymlinks($path) {
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function _extract($path, $arc) {
+        return false;
+    }
+
+    /**
+    * {@inheritdoc}
+    */
+    protected function _archive($dir, $files, $name, $arc) {
+        return false;
+    }
+
+}

+ 54 - 0
src/Chamilo/CoreBundle/Component/Editor/Driver/HomeDriver.php

@@ -0,0 +1,54 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\Driver;
+
+/**
+ * Class HomeDriver
+ * @package Chamilo\CoreBundle\Component\Editor\Driver
+ */
+class HomeDriver extends Driver
+{
+    public $name = 'HomeDriver';
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getConfiguration()
+    {
+        //if ($this->connector->security->isGranted('ROLE_ADMIN')) {
+        if (api_is_platform_admin()) {
+            $home = api_get_path(SYS_PATH).'home';
+
+            return array(
+                'driver' => 'HomeDriver',
+                'alias' => get_lang('Portal'),
+                'path' => $home,
+                'URL' => api_get_path(WEB_PATH) . 'home',
+                'accessControl' => array($this, 'access'),
+            );
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function upload($fp, $dst, $name, $tmpname)
+    {
+        $this->setConnectorFromPlugin();
+        if ($this->connector->security->isGranted('ROLE_ADMIN')) {
+            return parent::upload($fp, $dst, $name, $tmpname);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function rm($hash)
+    {
+        $this->setConnectorFromPlugin();
+        if ($this->connector->security->isGranted('ROLE_ADMIN')) {
+            return parent::rm($hash);
+        }
+    }
+}

+ 62 - 0
src/Chamilo/CoreBundle/Component/Editor/Driver/PersonalDriver.php

@@ -0,0 +1,62 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\Driver;
+
+/**
+ * Class PersonalDriver
+ * @todo add more checks in upload/rm
+ * @package Chamilo\CoreBundle\Component\Editor\Driver
+ */
+class PersonalDriver extends Driver
+{
+    public $name = 'PersonalDriver';
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getConfiguration()
+    {
+        //if ($this->connector->security->isGranted('IS_AUTHENTICATED_FULLY')) {
+            $userId = api_get_user_id();
+            if (!empty($userId)) {
+
+                // Adding user personal files
+                $dir = \UserManager::get_user_picture_path_by_id($userId, 'system');
+                $dirWeb = \UserManager::get_user_picture_path_by_id($userId, 'web');
+
+                $driver = array(
+                    'driver' => 'PersonalDriver',
+                    'alias' => get_lang('MyFiles'),
+                    'path' => $dir['dir'].'my_files',
+                    'URL' => $dirWeb['dir'].'my_files',
+                    'accessControl' => array($this, 'access')
+                );
+
+                return $driver;
+            }
+        //}
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function upload($fp, $dst, $name, $tmpname)
+    {
+        $this->setConnectorFromPlugin();
+        //if ($this->connector->security->isGranted('IS_AUTHENTICATED_FULLY')) {
+            return parent::upload($fp, $dst, $name, $tmpname);
+        //}
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function rm($hash)
+    {
+        $this->setConnectorFromPlugin();
+        //if ($this->connector->security->isGranted('IS_AUTHENTICATED_FULLY')) {
+            return parent::rm($hash);
+        //}
+    }
+}

+ 240 - 0
src/Chamilo/CoreBundle/Component/Editor/Editor.php

@@ -0,0 +1,240 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor;
+
+use Symfony\Component\Translation\Translator;
+use Symfony\Component\Routing\RouterInterface;
+use Chamilo\CoreBundle\Entity\Course;
+use Chamilo\CoreBundle\Framework\Template;
+
+/**
+ * Class Editor
+ * @package Chamilo\CoreBundle\Component\Editor
+ */
+class Editor
+{
+    /**
+     * Name of the instance.
+     *
+     * @access protected
+     * @var string
+     */
+    public $name;
+
+    /**
+     * Name of the toolbar to load.
+     *
+     * @var string
+     */
+    public $toolbarSet;
+
+    /**
+     * Initial value.
+     *
+     * @var string
+     */
+    public $value;
+
+    /**
+     * @var array
+     */
+    public $config;
+
+    /** @var Translator */
+    public $translator;
+
+    /** @var RouterInterface */
+    public $urlGenerator;
+
+    /** @var \Template */
+    public $template;
+
+    public function __construct()
+    {
+        $this->toolbarSet = 'Basic';
+        $this->value = '';
+        $this->config = array();
+        $this->setConfigAttribute('width', '100%');
+        $this->setConfigAttribute('height', '200');
+        $this->setConfigAttribute('fullPage', false);
+        /*$this->translator = $translator;
+        $this->urlGenerator = $urlGenerator;*/
+        //$this->course = $course;
+    }
+
+    /**
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * @param string $name
+     */
+    public function setName($name)
+    {
+        $this->name = $name;
+    }
+
+    /**
+     * Return the HTML code required to run editor.
+     *
+     * @return string
+     */
+    public function createHtml()
+    {
+        $html = '<textarea id="'.$this->getName().'" name="'.$this->getName().'">'.$this->value.'</textarea>';
+        //$html .= $this->editorReplace();
+        return $html;
+    }
+
+    /**
+     * @return string
+     */
+    public function editorReplace()
+    {
+        $toolbar = new Toolbar($this->toolbarSet, $this->config);
+        $toolbar->setLanguage($this->getLocale());
+        $config = $toolbar->getConfig();
+        $javascript = $this->toJavascript($config);
+        $html = "<script>
+           CKEDITOR.replace('".$this->name."',
+               $javascript
+           );
+           </script>";
+
+        return $html;
+    }
+
+    /**
+     * Converts a PHP variable into its Javascript equivalent.
+     * The code of this method has been "borrowed" from the function drupal_to_js() within the Drupal CMS.
+     * @param mixed $var    The variable to be converted into Javascript syntax
+     * @return string        Returns a string
+     * Note: This function is similar to json_encode(), in addition it produces HTML-safe strings, i.e. with <, > and & escaped.
+     * @link http://drupal.org/
+     */
+    protected function toJavascript($var)
+    {
+        switch (gettype($var)) {
+            case 'boolean':
+                return $var ? 'true' : 'false'; // Lowercase necessary!
+            case 'integer':
+            case 'double':
+                return (string)$var;
+            case 'resource':
+            case 'string':
+                return '"'.str_replace(
+                    array("\r", "\n", "<", ">", "&"),
+                    array('\r', '\n', '\x3c', '\x3e', '\x26'),
+                    addslashes($var)
+                ).'"';
+            case 'array':
+                // Arrays in JSON can't be associative. If the array is empty or if it
+                // has sequential whole number keys starting with 0, it's not associative
+                // so we can go ahead and convert it as an array.
+                if (empty($var) || array_keys($var) === range(0, sizeof($var) - 1)) {
+                    $output = array();
+                    foreach ($var as $v) {
+                        $output[] = $this->toJavascript($v);
+                    }
+
+                    return '[ '.implode(', ', $output).' ]';
+                }
+            case 'object':
+                // Otherwise, fall through to convert the array as an object.
+                $output = array();
+                foreach ($var as $k => $v) {
+                    $output[] = $this->toJavascript(strval($k)).': '.$this->toJavascript($v);
+                }
+
+                return '{ '.implode(', ', $output).' }';
+            default:
+                return 'null';
+        }
+    }
+
+    /**
+     * @param string $key
+     * @param mixed $value
+     */
+    public function setConfigAttribute($key, $value)
+    {
+        $this->config[$key] = $value;
+    }
+
+    /**
+     * @param string $key
+     * @return mixed
+     */
+    public function getConfigAttribute($key)
+    {
+        return isset($this->config[$key]) ? $this->config[$key] : null;
+    }
+
+    /**
+     * @param array $config
+     */
+    public function processConfig($config)
+    {
+        if (is_array($config)) {
+            foreach ($config as $key => $value) {
+                switch($key) {
+                    case 'ToolbarSet':
+                        $this->toolbarSet = $value;
+                        break;
+                    case 'Config':
+                        $this->processConfig($value);
+                        break;
+                    case 'Width':
+                        $this->setConfigAttribute('width', $value);
+                        break;
+                    case 'Height':
+                        $this->setConfigAttribute('height', $value);
+                        break;
+                    case 'FullPage':
+                        $this->setConfigAttribute('fullPage', $value);
+                        break;
+                    default:
+                        $this->setConfigAttribute($key, $value);
+                        break;
+                }
+            }
+        }
+    }
+
+    /**
+     * @return null
+     */
+    public function getEditorTemplate()
+    {
+        return null;
+    }
+
+    /**
+     * @return string
+     */
+    public function getEditorStandAloneTemplate()
+    {
+        return 'javascript/editor/elfinder_standalone.tpl';
+    }
+
+    /**
+     * @return null
+     */
+    public function formatTemplates($templates)
+    {
+        return null;
+    }
+
+    /**
+     * @return string
+     */
+    public function getLocale()
+    {
+        return 'en';
+    }
+}

+ 112 - 0
src/Chamilo/CoreBundle/Component/Editor/Finder.php

@@ -0,0 +1,112 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor;
+
+/**
+ * Class Finder
+ *
+ * This class just modifies this line:
+ * $class = 'elFinderVolume'.(isset($o['driver']) ? $o['driver'] : '');
+ * in order to use normal classes and not a custom 'elFinderVolume' class.
+ *
+ * @package Chamilo\CoreBundle\Component\Editor
+ */
+class Finder extends \elFinder
+{
+
+    /**
+     * Constructor
+     *
+     * @param  array  elFinder and roots configurations
+     * @return void
+     * @author Dmitry (dio) Levashov
+     **/
+    public function __construct($opts)
+    {
+        if (session_id() == '') {
+            session_start();
+        }
+
+        $this->time  = $this->utime();
+        $this->debug = (isset($opts['debug']) && $opts['debug'] ? true : false);
+        $this->timeout = (isset($opts['timeout']) ? $opts['timeout'] : 0);
+        $this->netVolumesSessionKey = !empty($opts['netVolumesSessionKey'])? $opts['netVolumesSessionKey'] : 'elFinderNetVolumes';
+        $this->callbackWindowURL = (isset($opts['callbackWindowURL']) ? $opts['callbackWindowURL'] : '');
+
+        // setlocale and global locale regists to elFinder::locale
+        self::$locale = !empty($opts['locale']) ? $opts['locale'] : 'en_US.UTF-8';
+        if (false === @setlocale(LC_ALL, self::$locale)) {
+            self::$locale = setlocale(LC_ALL, '');
+        }
+
+        // bind events listeners
+        if (!empty($opts['bind']) && is_array($opts['bind'])) {
+            $_req = $_SERVER["REQUEST_METHOD"] == 'POST' ? $_POST : $_GET;
+            $_reqCmd = isset($_req['cmd']) ? $_req['cmd'] : '';
+            foreach ($opts['bind'] as $cmd => $handlers) {
+                $doRegist = (strpos($cmd, '*') !== false);
+                if (! $doRegist) {
+                    $_getcmd = create_function('$cmd', 'list($ret) = explode(\'.\', $cmd);return trim($ret);');
+                    $doRegist = ($_reqCmd && in_array($_reqCmd, array_map($_getcmd, explode(' ', $cmd))));
+                }
+                if ($doRegist) {
+                    if (! is_array($handlers) || is_object($handlers[0])) {
+                        $handlers = array($handlers);
+                    }
+                    foreach($handlers as $handler) {
+                        if ($handler) {
+                            if (is_string($handler) && strpos($handler, '.')) {
+                                list($_domain, $_name, $_method) = array_pad(explode('.', $handler), 3, '');
+                                if (strcasecmp($_domain, 'plugin') === 0) {
+                                    if ($plugin = $this->getPluginInstance($_name, isset($opts['plugin'][$_name])? $opts['plugin'][$_name] : array())
+                                        and method_exists($plugin, $_method)) {
+                                        $this->bind($cmd, array($plugin, $_method));
+                                    }
+                                }
+                            } else {
+                                $this->bind($cmd, $handler);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        if (!isset($opts['roots']) || !is_array($opts['roots'])) {
+            $opts['roots'] = array();
+        }
+
+        // check for net volumes stored in session
+        foreach ($this->getNetVolumes() as $root) {
+            $opts['roots'][] = $root;
+        }
+
+        // "mount" volumes
+        foreach ($opts['roots'] as $i => $o) {
+            //$class = 'elFinderVolume'.(isset($o['driver']) ? $o['driver'] : '');
+            $class = isset($o['driver']) ? $o['driver'] : '';
+
+            if (class_exists($class)) {
+                $volume = new $class();
+
+                if ($volume->mount($o)) {
+                    // unique volume id (ends on "_") - used as prefix to files hash
+                    $id = $volume->id();
+
+                    $this->volumes[$id] = $volume;
+                    if (!$this->default && $volume->isReadable()) {
+                        $this->default = $this->volumes[$id];
+                    }
+                } else {
+                    $this->mountErrors[] = 'Driver "'.$class.'" : '.implode(' ', $volume->error());
+                }
+            } else {
+                $this->mountErrors[] = 'Driver "'.$class.'" does not exists';
+            }
+        }
+
+        // if at least one readable volume - ii desu >_<
+        $this->loaded = !empty($this->default);
+    }
+}

+ 82 - 0
src/Chamilo/CoreBundle/Component/Editor/TinyMce/TinyMce.php

@@ -0,0 +1,82 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\TinyMce;
+
+use Chamilo\CoreBundle\Component\Editor\Editor;
+use Chamilo\CoreBundle\Component\Editor\TinyMce\Toolbar;
+
+/**
+ * Class TinyMce
+ * @package Chamilo\CoreBundle\Component\Editor\TinyMce
+ */
+class TinyMce extends Editor
+{
+    /**
+     * Set js to be include in the template
+     */
+    public function setJavascriptToInclude()
+    {
+        $jsFolder = api_get_path(WEB_LIBRARY_JS_PATH);
+        $this->template->addResource($jsFolder.'tinymce/tinymce.min.js', 'js');
+    }
+
+    /**
+     * @return string
+     */
+    public function getEditorTemplate()
+    {
+        return 'javascript/editor/tinymce/elfinder.tpl';
+    }
+
+    /**
+     * Return the HTML code required to run editor.
+     *
+     * @return string
+     */
+    public function createHtml()
+    {
+        $html = '<textarea id="'.$this->name.'" name="'.$this->name.'" class="ckeditor" >'.$this->value.'</textarea>';
+        $html .= $this->editorReplace();
+
+        return $html;
+    }
+
+    /**
+     * @return string
+     */
+    public function editorReplace()
+    {
+        $toolbar  = new Toolbar\Basic($this->urlGenerator, $this->toolbarSet, $this->config, 'TinyMce');
+        $toolbar->setLanguage($this->getLocale());
+        $config = $toolbar->getConfig();
+        $config['selector'] = "#".$this->name;
+        $javascript = $this->toJavascript($config);
+        $javascript = str_replace('"elFinderBrowser"', "elFinderBrowser", $javascript);
+
+        $html = "<script>
+            function elFinderBrowser (field_name, url, type, win) {
+                tinymce.activeEditor.windowManager.open({
+                    file: '".$this->urlGenerator->generate('filemanager')."',
+                    title: 'elFinder 2.0',
+                    width: 900,
+                    height: 450,
+                    resizable: 'yes'
+                    }, {
+                    setUrl: function (url) {
+                        win.document.getElementById(field_name).value = url;
+                    }
+                });
+                return false;
+            }
+
+            $(document).ready(function() {
+                tinymce.init(
+                    $javascript
+                 );
+             });
+        </script>";
+
+        return $html;
+    }
+}

+ 38 - 0
src/Chamilo/CoreBundle/Component/Editor/TinyMce/Toolbar/Basic.php

@@ -0,0 +1,38 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor\TinyMce\Toolbar;
+
+use Chamilo\CoreBundle\Component\Editor\Toolbar;
+
+/**
+ * Class Basic
+ * @package Chamilo\CoreBundle\Component\Editor\TinyMce\Toolbar\Basic
+ */
+class Basic extends Toolbar
+{
+    public function getConfig()
+    {
+        $config = array(
+            'theme' =>  "modern",
+            'width'=> 300,
+            'height'=> 300,
+            'plugins'=> array(
+                "advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker",
+                "searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking",
+                "save table contextmenu directionality emoticons template paste textcolor"
+            ),
+           'content_css'=> "css/content.css",
+           'toolbar' => "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | l      ink image | print preview media fullpage | forecolor backcolor emoticons",
+            'file_browser_callback' => 'elFinderBrowser'
+        );
+
+        if (isset($this->config)) {
+            $this->config = array_merge($config, $this->config);
+        } else {
+            $this->config = $config;
+        }
+
+        return $this->config;
+    }
+}

+ 120 - 0
src/Chamilo/CoreBundle/Component/Editor/Toolbar.php

@@ -0,0 +1,120 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Component\Editor;
+
+//use Symfony\Component\Routing\RouterInterface;
+
+/**
+ * Class Toolbar
+ * @package Chamilo\CoreBundle\Component\Editor
+ */
+class Toolbar
+{
+    public $config = array();
+    public $urlGenerator;
+    public $plugins = array();
+    public $defaultPlugins = array();
+
+    /**
+     * @param string $toolbar
+     * @param array $config
+     * @param string $prefix
+     */
+    public function __construct(
+        $toolbar = null,
+        $config = array(),
+        $prefix = null
+    ) {
+        if (!empty($toolbar)) {
+            $class = __NAMESPACE__."\\".$prefix."\\Toolbar\\".$toolbar;
+            if (class_exists($class)) {
+                $toolbarObj = new $class();
+                $this->setConfig($toolbarObj->getConfig());
+            }
+        }
+
+        if (!empty($config)) {
+            $this->updateConfig($config);
+        }
+        //$this->urlGenerator = $urlGenerator;
+    }
+
+    /**
+     * @return string
+     */
+    public function getPluginsToString()
+    {
+        $plugins = array_filter(array_merge($this->getDefaultPlugins(), $this->getPlugins()));
+
+        return
+            $this->getConfigAttribute('extraPlugins').
+            implode(',', $plugins);
+    }
+
+    /**
+     * @return array
+     */
+    public function getPlugins()
+    {
+        return $this->plugins;
+    }
+
+    /**
+     * @return array
+     */
+    public function getDefaultPlugins()
+    {
+        return $this->defaultPlugins;
+    }
+
+    /**
+     * @param array $config
+     */
+    public function setConfig(array $config)
+    {
+        $this->config = $config;
+    }
+
+    /**
+     * @param array $config
+     */
+    public function updateConfig(array $config)
+    {
+        if (empty($this->config)) {
+            $this->setConfig($config);
+        } else {
+            $this->config = array_merge($this->config, $config);
+        }
+    }
+
+    /**
+     * @return array
+     */
+    public function getConfig()
+    {
+        return $this->config;
+    }
+
+    /**
+     * @param string $variable
+     *
+     * @return array
+     */
+    public function getConfigAttribute($variable)
+    {
+        if (isset($this->config[$variable])) {
+            return $this->config[$variable];
+        }
+
+        return null;
+    }
+
+    /**
+     * @param string $language
+     */
+    public function setLanguage($language)
+    {
+        $this->config['language'] = $language;
+    }
+}