diff --git a/main/inc/lib/elfinder/connectorAction.php b/main/inc/lib/elfinder/connectorAction.php new file mode 100644 index 0000000000..74456e8051 --- /dev/null +++ b/main/inc/lib/elfinder/connectorAction.php @@ -0,0 +1,25 @@ +setDriverList($driverList); + +$operations = $connector->getOperations(); + +// Run elFinder +$finder = new Finder($operations); +$elFinderConnector = new \elFinderConnector($finder); +$elFinderConnector->run(); diff --git a/main/inc/lib/elfinder/filemanager.php b/main/inc/lib/elfinder/filemanager.php new file mode 100644 index 0000000000..f42dc9346e --- /dev/null +++ b/main/inc/lib/elfinder/filemanager.php @@ -0,0 +1,7 @@ +display('default/javascript/editor/ckeditor/elfinder.tpl'); diff --git a/main/inc/lib/elfinder/templates.php b/main/inc/lib/elfinder/templates.php new file mode 100644 index 0000000000..8e970c0d17 --- /dev/null +++ b/main/inc/lib/elfinder/templates.php @@ -0,0 +1,17 @@ +simpleFormatTemplates($templates); +$template->assign('templates', $templates); +$template->display('default/javascript/editor/ckeditor/templates.tpl'); diff --git a/main/inc/lib/formvalidator/Element/html_editor.php b/main/inc/lib/formvalidator/Element/html_editor.php index dfc070c55d..f2bafb59f6 100755 --- a/main/inc/lib/formvalidator/Element/html_editor.php +++ b/main/inc/lib/formvalidator/Element/html_editor.php @@ -1,125 +1,98 @@ _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 = ''; - $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 = ''; + $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 .= ''.get_lang('AllowedHTMLTags').''; return $result; } } diff --git a/main/inc/lib/formvalidator/FormValidator.class.php b/main/inc/lib/formvalidator/FormValidator.class.php index b23df384e8..252b68e0ac 100755 --- a/main/inc/lib/formvalidator/FormValidator.class.php +++ b/main/inc/lib/formvalidator/FormValidator.class.php @@ -1,9 +1,6 @@ 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); } /** diff --git a/main/inc/lib/template.lib.php b/main/inc/lib/template.lib.php index 8ab7e14191..65f6f23511 100755 --- a/main/inc/lib/template.lib.php +++ b/main/inc/lib/template.lib.php @@ -1,9 +1,6 @@ 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 .= ''; //Loading email_editor js if (!api_is_anonymous() && api_get_setting('allow_email_editor') == 'true') { diff --git a/main/newscorm/lp_add_item.php b/main/newscorm/lp_add_item.php index c184063e8e..3ff2394fac 100755 --- a/main/newscorm/lp_add_item.php +++ b/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(); + }); +}); '; /* 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 '
'; + echo '
'; } echo ''; diff --git a/main/newscorm/lp_edit_item.php b/main/newscorm/lp_edit_item.php index 0b53ec6c42..3e62e93cd5 100755 --- a/main/newscorm/lp_edit_item.php +++ b/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(); + }); +}); '; /* 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 '

'; echo '
'; echo '
'; } else { - echo $_SESSION['oLP']->return_new_tree(); + echo $_SESSION['oLP']->return_new_tree(); } - + echo ''; echo '
'; @@ -169,4 +174,4 @@ echo '
'; echo ''; /* FOOTER */ -Display::display_footer(); \ No newline at end of file +Display::display_footer(); diff --git a/main/template/default/javascript/editor/ckeditor/config_js.tpl b/main/template/default/javascript/editor/ckeditor/config_js.tpl new file mode 100644 index 0000000000..52d6cd8b84 --- /dev/null +++ b/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'}}'; +}; diff --git a/main/template/default/javascript/editor/ckeditor/elfinder.tpl b/main/template/default/javascript/editor/ckeditor/elfinder.tpl new file mode 100644 index 0000000000..17137103c8 --- /dev/null +++ b/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/' %} + + + + + + + + + + +
+{% endblock %} diff --git a/main/template/default/javascript/editor/ckeditor/templates.tpl b/main/template/default/javascript/editor/ckeditor/templates.tpl new file mode 100644 index 0000000000..5bbf1df89d --- /dev/null +++ b/main/template/default/javascript/editor/ckeditor/templates.tpl @@ -0,0 +1,6 @@ +CKEDITOR.addTemplates("default", +{ + imagesPath: ' ', + templates: + {{ templates }} +}); \ No newline at end of file diff --git a/main/template/default/layout/footer.tpl b/main/template/default/layout/footer.tpl index d3fdb29c11..6898883e29 100755 --- a/main/template/default/layout/footer.tpl +++ b/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 %} {{ execution_stats }} diff --git a/main/template/default/layout/head.tpl b/main/template/default/layout/head.tpl index 0ff71c5678..28b572656b 100755 --- a/main/template/default/layout/head.tpl +++ b/main/template/default/layout/head.tpl @@ -15,11 +15,76 @@ {{ css_file_to_string }} {{ css_style_print }} {{ js_file_to_string }} + {{ extra_headers }} "; + + 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); + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Basic.php b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Basic.php new file mode 100644 index 0000000000..5ca5881898 --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Basic.php @@ -0,0 +1,106 @@ + '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; + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Documents.php b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Documents.php new file mode 100644 index 0000000000..b6e9db4788 --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Documents.php @@ -0,0 +1,58 @@ + '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; + } + +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/IntroductionTool.php b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/IntroductionTool.php new file mode 100644 index 0000000000..480034deb4 --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/IntroductionTool.php @@ -0,0 +1,40 @@ + '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; + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/LearningPathDocuments.php b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/LearningPathDocuments.php new file mode 100644 index 0000000000..778df65554 --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/LearningPathDocuments.php @@ -0,0 +1,39 @@ + '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; + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Message.php b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Message.php new file mode 100644 index 0000000000..a1dd48a399 --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Message.php @@ -0,0 +1,35 @@ + '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; + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Notebook.php b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Notebook.php new file mode 100644 index 0000000000..5409ff8f6a --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/Notebook.php @@ -0,0 +1,13 @@ + '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; + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestFreeAnswerStrict.php b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestFreeAnswerStrict.php new file mode 100644 index 0000000000..363993671b --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestFreeAnswerStrict.php @@ -0,0 +1,54 @@ + '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; + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestProposedAnswer.php b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestProposedAnswer.php new file mode 100644 index 0000000000..cd7475380e --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestProposedAnswer.php @@ -0,0 +1,36 @@ + '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; + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestQuestionDescription.php b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestQuestionDescription.php new file mode 100644 index 0000000000..13829f2e0f --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestQuestionDescription.php @@ -0,0 +1,40 @@ + '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; + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/ToolbarStartExpanded.php b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/ToolbarStartExpanded.php new file mode 100644 index 0000000000..cf6d858527 --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/ToolbarStartExpanded.php @@ -0,0 +1,14 @@ + '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; + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/WikiStudent.php b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/WikiStudent.php new file mode 100644 index 0000000000..3ad45c3a17 --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/WikiStudent.php @@ -0,0 +1,13 @@ +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; + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/Driver/CourseDriver.php b/src/Chamilo/CoreBundle/Component/Editor/Driver/CourseDriver.php new file mode 100644 index 0000000000..d4a3dad565 --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/Driver/CourseDriver.php @@ -0,0 +1,163 @@ +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; + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/Driver/CourseUserDriver.php b/src/Chamilo/CoreBundle/Component/Editor/Driver/CourseUserDriver.php new file mode 100644 index 0000000000..b543073b7d --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/Driver/CourseUserDriver.php @@ -0,0 +1,37 @@ +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' + ); + } + } + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/Driver/Driver.php b/src/Chamilo/CoreBundle/Component/Editor/Driver/Driver.php new file mode 100644 index 0000000000..8b2dc73bda --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/Driver/Driver.php @@ -0,0 +1,63 @@ +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']); + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/Driver/DriverInterface.php b/src/Chamilo/CoreBundle/Component/Editor/Driver/DriverInterface.php new file mode 100644 index 0000000000..fdc6e06c97 --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/Driver/DriverInterface.php @@ -0,0 +1,41 @@ +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; + } + +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/Driver/HomeDriver.php b/src/Chamilo/CoreBundle/Component/Editor/Driver/HomeDriver.php new file mode 100644 index 0000000000..292d4e4dd1 --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/Driver/HomeDriver.php @@ -0,0 +1,54 @@ +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); + } + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/Driver/PersonalDriver.php b/src/Chamilo/CoreBundle/Component/Editor/Driver/PersonalDriver.php new file mode 100644 index 0000000000..91eaeafe6b --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/Driver/PersonalDriver.php @@ -0,0 +1,62 @@ +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); + //} + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/Editor.php b/src/Chamilo/CoreBundle/Component/Editor/Editor.php new file mode 100644 index 0000000000..8ad5708ca2 --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/Editor.php @@ -0,0 +1,240 @@ +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 = ''; + //$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 = ""; + + 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'; + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/Finder.php b/src/Chamilo/CoreBundle/Component/Editor/Finder.php new file mode 100644 index 0000000000..b970897f57 --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/Finder.php @@ -0,0 +1,112 @@ +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); + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/TinyMce/TinyMce.php b/src/Chamilo/CoreBundle/Component/Editor/TinyMce/TinyMce.php new file mode 100644 index 0000000000..78a39e44f9 --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/TinyMce/TinyMce.php @@ -0,0 +1,82 @@ +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 = ''; + $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 = ""; + + return $html; + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/TinyMce/Toolbar/Basic.php b/src/Chamilo/CoreBundle/Component/Editor/TinyMce/Toolbar/Basic.php new file mode 100644 index 0000000000..006c17a934 --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/TinyMce/Toolbar/Basic.php @@ -0,0 +1,38 @@ + "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; + } +} diff --git a/src/Chamilo/CoreBundle/Component/Editor/Toolbar.php b/src/Chamilo/CoreBundle/Component/Editor/Toolbar.php new file mode 100644 index 0000000000..5a61fbbe4b --- /dev/null +++ b/src/Chamilo/CoreBundle/Component/Editor/Toolbar.php @@ -0,0 +1,120 @@ +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; + } +}