Просмотр исходного кода

Add highlighted document for learnin paths - refs BT#14334

Angel Fernando Quiroz Campos 6 лет назад
Родитель
Сommit
1062b71bd1

BIN
main/img/lp_highlighted_document.png


+ 1 - 0
main/inc/lib/api.lib.php

@@ -104,6 +104,7 @@ define('SURVEY_VISIBLE_PUBLIC', 2);
 /* When you add a new tool you must add it into function api_get_tools_lists() too */
 define('TOOL_DOCUMENT', 'document');
 define('TOOL_LP_FINAL_ITEM', 'final_item');
+define('TOOL_HIGHLIGHTED_DOCUMENT', 'highlighted_document');
 define('TOOL_THUMBNAIL', 'thumbnail');
 define('TOOL_HOTPOTATOES', 'hotpotatoes');
 define('TOOL_CALENDAR_EVENT', 'calendar_event');

+ 37 - 0
main/inc/lib/javascript/highlighted_document/css/start.css

@@ -0,0 +1,37 @@
+body {
+    font-size: 25px;
+    line-height: 1.25em !important;
+    text-align: justify;
+    -webkit-touch-callout: none;
+    -webkit-user-select: none;
+    -khtml-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+}
+
+.text-highlight {
+    -webkit-transition: color .3s linear, text-shadow .3s linear;
+    -khtml-transition: color .3s linear, text-shadow .3s linear;
+    -moz-transition: color .3s linear, text-shadow .3s linear;
+    -ms-transition: color .3s linear, text-shadow .3s linear;
+    transition: color .3s linear, text-shadow .3s linear;
+}
+
+.text-highlight.active {
+    color: red;
+    -webkit-text-shadow: 0px 0px 1px rgba(255, 0, 0, 1);
+    -khtml-text-shadow: 0px 0px 1px rgba(255, 0, 0, 1);
+    -moz-text-shadow: 0px 0px 1px rgba(255, 0, 0, 1);
+    -ms-text-shadow: 0px 0px 1px rgba(255, 0, 0, 1);
+    text-shadow: 0px 0px 1px rgba(255, 0, 0, 1);
+    -webkit-transition: color .3s linear, text-shadow .3s linear;
+    -khtml-transition: color .3s linear, text-shadow .3s linear;
+    -moz-transition: color .3s linear, text-shadow .3s linear;
+    -ms-transition: color .3s linear, text-shadow .3s linear;
+    transition: color .3s linear, text-shadow .3s linear;
+}
+
+br {
+    margin-bottom: 1em;
+}

+ 79 - 0
main/inc/lib/javascript/highlighted_document/js/start.js

@@ -0,0 +1,79 @@
+/* For licensing terms, see /license.txt */
+
+$(function () {
+    var parent$ = window.parent.$,
+        $player = parent$('audio#lp_audio_media_player_html5');
+
+    if ($player.length === 0) {
+        $player = parent$('audio#lp_audio_media_player');
+    }
+
+    var player = $player.get(0),
+        def = $.Deferred();
+
+    if (!$player.length) {
+        processText(wordsCount);
+
+        return;
+    }
+
+    player.preload = 'auto';
+
+    function processText(turns) {
+        var tagEnd = '</span> ',
+            tagStart = tagEnd + '<span class="text-highlight">',
+            wordsPerSecond = Math.ceil(wordsCount / turns);
+
+        var indexes = Object.keys(words);
+
+        var output = '';
+
+        for (var i = 0; i < turns; i++) {
+            var block = indexes.slice(i * wordsPerSecond, i * wordsPerSecond + wordsPerSecond),
+                index = block[0];
+
+            if (!index) {
+                continue;
+            }
+
+            output += tagStart + words[index];
+
+            for (var j = 1; j < block.length; j++) {
+                index = block[j];
+                output += ' ' + words[index];
+            }
+        }
+
+        output += tagEnd;
+        output = output.slice(tagEnd.length);
+
+        $('.page-blank').html(output);
+
+        def.resolve(output);
+
+        return def.promise();
+    }
+
+    player.ontimeupdate = function () {
+        var block = Math.ceil(this.currentTime);
+
+        $('.text-highlight')
+            .removeClass('active')
+            .filter(function (index) {
+                return index + 1 == block;
+            })
+            .addClass('active');
+    };
+    player.onloadedmetadata = function () {
+        var turns = Math.ceil(this.duration);
+
+        processText(turns)
+            .then(function (output) {
+                var to = window.setTimeout(function () {
+                    player.play();
+
+                    window.clearTimeout(to);
+                }, 1500);
+            });
+    }
+});

+ 75 - 0
main/lp/highlighted_document.php

@@ -0,0 +1,75 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+/**
+ * Print a highlighted document inside a session
+ *
+ * @package chamilo.learnpath
+ */
+
+use Chamilo\CourseBundle\Entity\CDocument;
+
+$_in_course = true;
+
+require_once __DIR__.'/../inc/global.inc.php';
+
+$current_course_tool = TOOL_LEARNPATH;
+
+api_protect_course_script(true);
+
+$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
+$lpId = isset($_GET['lp_id']) ? intval($_GET['lp_id']) : 0;
+$courseInfo = api_get_course_info();
+$courseCode = $courseInfo['code'];
+$courseId = $courseInfo['real_id'];
+$userId = api_get_user_id();
+$sessionId = api_get_session_id();
+
+$em = Database::getManager();
+$documentRepo = $em->getRepository('ChamiloCourseBundle:CDocument');
+
+// This page can only be shown from inside a learning path
+if (!$id && !$lpId) {
+    api_not_allowed(true);
+    exit;
+}
+
+/** @var CDocument $document */
+$document = $documentRepo->findOneBy(['cId' => $courseId, 'iid' => $id]);
+
+if (empty($document)) {
+    // Try with normal id
+    /** @var CDocument $document */
+    $document = $documentRepo->findOneBy(['cId' => $courseId, 'id' => $id]);
+
+    if (empty($document)) {
+        Display::return_message(get_lang('FileNotFound'), 'error');
+        exit;
+    }
+}
+
+$documentPathInfo = pathinfo($document->getPath());
+$jplayer_supported_files = ['mp4', 'ogv', 'flv', 'm4v'];
+$extension = isset($documentPathInfo['extension']) ? $documentPathInfo['extension'] : '';
+
+$coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['directory'];
+$documentPath = '/document'.$document->getPath();
+$documentText = file_get_contents($coursePath.$documentPath);
+$documentText = api_remove_tags_with_space($documentText);
+
+$words = array_map(
+    function ($word) {
+        return nl2br($word);
+    },
+    str_word_count($documentText, 2, '0..9'."\n")
+);
+
+$htmlHeadXtra[] = '<script>
+    var words = '.json_encode($words, JSON_OBJECT_AS_ARRAY).',
+        wordsCount = '.count($words).'
+</script>';
+$htmlHeadXtra[] = api_get_js('highlighted_document/js/start.js');
+$htmlHeadXtra[] = api_get_css(api_get_path(WEB_LIBRARY_JS_PATH).'highlighted_document/css/start.css');
+
+$template = new Template(strip_tags($document->getTitle()));
+$template->display_blank_template();

+ 498 - 16
main/lp/learnpath.class.php

@@ -6,6 +6,7 @@ use Chamilo\CoreBundle\Entity\Repository\ItemPropertyRepository;
 use Chamilo\CourseBundle\Component\CourseCopy\CourseArchiver;
 use Chamilo\CourseBundle\Component\CourseCopy\CourseBuilder;
 use Chamilo\CourseBundle\Component\CourseCopy\CourseRestorer;
+use Chamilo\CourseBundle\Entity\CDocument;
 use Chamilo\CourseBundle\Entity\CItemProperty;
 use Chamilo\CourseBundle\Entity\CLp;
 use Chamilo\CourseBundle\Entity\CLpCategory;
@@ -2300,22 +2301,30 @@ class learnpath
 
         if (!empty($row['audio'])) {
             $list = $_SESSION['oLP']->get_toc();
-            $type_quiz = false;
 
-            foreach ($list as $toc) {
-                if ($toc['id'] == $_SESSION['oLP']->current && $toc['type'] == 'quiz') {
-                    $type_quiz = true;
-                }
-            }
+            switch ($row['item_type']) {
+                case 'quiz':
+                    $type_quiz = false;
 
-            if ($type_quiz) {
-                if ($_SESSION['oLP']->prevent_reinit == 1) {
-                    $autostart_audio = $row['status'] === 'completed' ? 'false' : 'true';
-                } else {
-                    $autostart_audio = $autostart;
-                }
-            } else {
-                $autostart_audio = 'true';
+                    foreach ($list as $toc) {
+                        if ($toc['id'] == $_SESSION['oLP']->current) {
+                            $type_quiz = true;
+                        }
+                    }
+
+                    if ($type_quiz) {
+                        if ($_SESSION['oLP']->prevent_reinit == 1) {
+                            $autostart_audio = $row['status'] === 'completed' ? 'false' : 'true';
+                        } else {
+                            $autostart_audio = $autostart;
+                        }
+                    }
+                    break;
+                case 'highlighted_document':
+                    $autostart_audio = 'false';
+                    break;
+                default:
+                    $autostart_audio = 'true';
             }
 
             $courseInfo = api_get_course_info();
@@ -6249,7 +6258,7 @@ class learnpath
             $title_cut = cut($arrLP[$i]['title'], self::MAX_LP_ITEM_TITLE_LENGTH);
 
             // Link for the documents
-            if ($arrLP[$i]['item_type'] == 'document') {
+            if ($arrLP[$i]['item_type'] == 'document' || $arrLP[$i]['item_type'] == TOOL_HIGHLIGHTED_DOCUMENT) {
                 $url = $mainUrl.'&action=view_item&mode=preview_document&id='.$arrLP[$i]['id'].'&lp_id='.$this->lp_id;
                 $title_cut = Display::url(
                     $title_cut,
@@ -6462,6 +6471,7 @@ class learnpath
                 switch ($arrLP[$i]['item_type']) {
                     case TOOL_DOCUMENT:
                     case TOOL_LP_FINAL_ITEM:
+                    case TOOL_HIGHLIGHTED_DOCUMENT:
                         $urlPreviewLink = $mainUrl.'&action=view_item&mode=preview_document&id='.$arrLP[$i]['id'].'&lp_id='.$this->lp_id;
                         $previewIcon = Display::url(
                             $previewImage,
@@ -7332,6 +7342,7 @@ class learnpath
                         $return .= $this->getSavedFinalItem();
                         break;
                     case TOOL_DOCUMENT:
+                    case TOOL_HIGHLIGHTED_DOCUMENT:
                         $tbl_doc = Database::get_course_table(TABLE_DOCUMENT);
                         $sql_doc = "SELECT path FROM ".$tbl_doc."
                                     WHERE c_id = ".$course_id." AND iid = ".intval($row['path']);
@@ -7435,6 +7446,27 @@ class learnpath
                     $row_step
                 );
                 break;
+            case TOOL_HIGHLIGHTED_DOCUMENT:
+                $tbl_doc = Database::get_course_table(TABLE_DOCUMENT);
+                $sql = "SELECT lp.*, doc.path as dir
+                        FROM $tbl_lp_item as lp
+                        LEFT JOIN $tbl_doc as doc
+                        ON (doc.iid = lp.path AND lp.c_id = doc.c_id)
+                        WHERE
+                            doc.c_id = $course_id AND
+                            lp.iid = ".$item_id;
+                $res_step = Database::query($sql);
+                $row_step = Database::fetch_array($res_step, 'ASSOC');
+                $return .= $this->display_manipulate(
+                    $item_id,
+                    $row['item_type']
+                );
+                $return .= $this->displayFrmHighlightedDocument(
+                    'edit',
+                    $item_id,
+                    $row_step
+                );
+                break;
             case TOOL_LINK:
                 $link_id = (string) $row['path'];
                 if (ctype_digit($link_id)) {
@@ -9100,6 +9132,451 @@ class learnpath
         return $form->returnForm();
     }
 
+    /**
+     * Returns the form to update or create a highlighted document.
+     *
+     * @param string $action     "add" or "edit"
+     * @param int    $id         ID of the lp_item (if already exists)
+     * @param mixed  $extra_info Integer if document ID, string if info ('new')
+     *
+     * @throws Exception
+     * @throws HTML_QuickForm_Error
+     *
+     * @return string HTML form
+     */
+    public function displayFrmHighlightedDocument($action = 'add', $id = 0, $extra_info = 'new')
+    {
+        $course_id = api_get_course_int_id();
+        $_course = api_get_course_info();
+        $tbl_lp_item = Database::get_course_table(TABLE_LP_ITEM);
+        $tbl_doc = Database::get_course_table(TABLE_DOCUMENT);
+
+        $no_display_edit_textarea = false;
+        $item_description = '';
+        //If action==edit document
+        //We don't display the document form if it's not an editable document (html or txt file)
+        if ($action == 'edit') {
+            if (is_array($extra_info)) {
+                $path_parts = pathinfo($extra_info['dir']);
+                if ($path_parts['extension'] != "txt" && $path_parts['extension'] != "html") {
+                    $no_display_edit_textarea = true;
+                }
+            }
+        }
+        $no_display_add = false;
+
+        if ($id != 0 && is_array($extra_info)) {
+            $item_title = stripslashes($extra_info['title']);
+            $item_description = stripslashes($extra_info['description']);
+            $item_terms = stripslashes($extra_info['terms']);
+            if (empty($item_title)) {
+                $path_parts = pathinfo($extra_info['path']);
+                $item_title = stripslashes($path_parts['filename']);
+            }
+        } elseif (is_numeric($extra_info)) {
+            $sql = "SELECT path, title FROM $tbl_doc WHERE c_id = ".$course_id." AND iid = ".intval($extra_info);
+            $result = Database::query($sql);
+            $row = Database::fetch_array($result);
+            $item_title = $row['title'];
+            $item_title = str_replace('_', ' ', $item_title);
+            if (empty($item_title)) {
+                $path_parts = pathinfo($row['path']);
+                $item_title = stripslashes($path_parts['filename']);
+            }
+        } else {
+            $item_title = '';
+            $item_description = '';
+        }
+
+        if ($id != 0 && is_array($extra_info)) {
+            $parent = $extra_info['parent_item_id'];
+        } else {
+            $parent = 0;
+        }
+
+        $sql = "SELECT * FROM $tbl_lp_item WHERE c_id = $course_id AND lp_id = ".$this->lp_id;
+        $result = Database::query($sql);
+        $arrLP = [];
+
+        while ($row = Database::fetch_array($result)) {
+            $arrLP[] = [
+                'id' => $row['iid'],
+                'item_type' => $row['item_type'],
+                'title' => $row['title'],
+                'path' => $row['path'],
+                'description' => $row['description'],
+                'parent_item_id' => $row['parent_item_id'],
+                'previous_item_id' => $row['previous_item_id'],
+                'next_item_id' => $row['next_item_id'],
+                'display_order' => $row['display_order'],
+                'max_score' => $row['max_score'],
+                'min_score' => $row['min_score'],
+                'mastery_score' => $row['mastery_score'],
+                'prerequisite' => $row['prerequisite'],
+            ];
+        }
+
+        $this->tree_array($arrLP);
+        $arrLP = isset($this->arrMenu) ? $this->arrMenu : [];
+        unset($this->arrMenu);
+
+        if ($action == 'add') {
+            $formHeader = get_lang('CreateTheDocument');
+        } else {
+            $formHeader = get_lang('EditTheCurrentDocument');
+        }
+
+        $form = new FormValidator(
+            'frm_add_reading',
+            'POST',
+            $this->getCurrentBuildingModeURL(),
+            '',
+            ['enctype' => 'multipart/form-data']
+        );
+        $form->addHeader($formHeader);
+        $defaults['title'] = !empty($item_title) ? Security::remove_XSS($item_title) : '';
+        $defaults['description'] = $item_description;
+
+        $data = $this->generate_lp_folder($_course);
+
+        if ($action != 'edit') {
+            $folders = DocumentManager::get_all_document_folders($_course, 0, true);
+            DocumentManager::build_directory_selector(
+                $folders,
+                '',
+                [],
+                true,
+                $form,
+                'directory_parent_id'
+            );
+        }
+
+        if (isset($data['id'])) {
+            $defaults['directory_parent_id'] = $data['id'];
+        }
+
+        $form->addElement(
+            'text',
+            'title',
+            get_lang('Title')
+        );
+        $form->applyFilter('title', 'trim');
+        $form->applyFilter('title', 'html_filter');
+
+        $arrHide[0]['value'] = $this->name;
+        $arrHide[0]['padding'] = 20;
+
+        for ($i = 0; $i < count($arrLP); $i++) {
+            if ($action != 'add') {
+                if ($arrLP[$i]['item_type'] == 'dir' &&
+                    !in_array($arrLP[$i]['id'], $arrHide) &&
+                    !in_array($arrLP[$i]['parent_item_id'], $arrHide)
+                ) {
+                    $arrHide[$arrLP[$i]['id']]['value'] = $arrLP[$i]['title'];
+                    $arrHide[$arrLP[$i]['id']]['padding'] = 20 + $arrLP[$i]['depth'] * 20;
+                }
+            } else {
+                if ($arrLP[$i]['item_type'] == 'dir') {
+                    $arrHide[$arrLP[$i]['id']]['value'] = $arrLP[$i]['title'];
+                    $arrHide[$arrLP[$i]['id']]['padding'] = 20 + $arrLP[$i]['depth'] * 20;
+                }
+            }
+        }
+
+        $parent_select = $form->addSelect(
+            'parent',
+            get_lang('Parent'),
+            [],
+            ['onchange' => "javascript: load_cbo(this.value, 'frm_add_reading_previous');"]
+        );
+
+        $my_count = 0;
+        foreach ($arrHide as $key => $value) {
+            if ($my_count != 0) {
+                // The LP name is also the first section and is not in the same charset like the other sections.
+                $value['value'] = Security::remove_XSS($value['value']);
+                $parent_select->addOption(
+                    $value['value'],
+                    $key,
+                    'style="padding-left:'.$value['padding'].'px;"'
+                );
+            } else {
+                $value['value'] = Security::remove_XSS($value['value']);
+                $parent_select->addOption(
+                    $value['value'],
+                    $key,
+                    'style="padding-left:'.$value['padding'].'px;"'
+                );
+            }
+            $my_count++;
+        }
+
+        if (!empty($id)) {
+            $parent_select->setSelected($parent);
+        } else {
+            $parent_item_id = Session::read('parent_item_id', 0);
+            $parent_select->setSelected($parent_item_id);
+        }
+
+        if (is_array($arrLP)) {
+            reset($arrLP);
+        }
+
+        $arrHide = [];
+        $s_selected_position = null;
+
+        // POSITION
+        $lastPosition = null;
+
+        for ($i = 0; $i < count($arrLP); $i++) {
+            if (($arrLP[$i]['parent_item_id'] == $parent && $arrLP[$i]['id'] != $id) ||
+                $arrLP[$i]['item_type'] == TOOL_LP_FINAL_ITEM
+            ) {
+                if ((isset($extra_info['previous_item_id']) &&
+                    $extra_info['previous_item_id'] == $arrLP[$i]['id']) || $action == 'add'
+                ) {
+                    $s_selected_position = $arrLP[$i]['id'];
+                }
+                $arrHide[$arrLP[$i]['id']]['value'] = get_lang('After').' "'.$arrLP[$i]['title'].'"';
+            }
+            $lastPosition = $arrLP[$i]['id'];
+        }
+
+        if (empty($s_selected_position)) {
+            $s_selected_position = $lastPosition;
+        }
+
+        $position = $form->addSelect(
+            'previous',
+            get_lang('Position'),
+            []
+        );
+        $position->addOption(get_lang('FirstPosition'), 0);
+
+        foreach ($arrHide as $key => $value) {
+            $padding = isset($value['padding']) ? $value['padding'] : 20;
+            $position->addOption(
+                $value['value'],
+                $key,
+                'style="padding-left:'.$padding.'px;"'
+            );
+        }
+        $position->setSelected($s_selected_position);
+
+        if (is_array($arrLP)) {
+            reset($arrLP);
+        }
+
+        $arrHide = [];
+
+        for ($i = 0; $i < count($arrLP); $i++) {
+            if ($arrLP[$i]['id'] != $id && $arrLP[$i]['item_type'] != 'dir' &&
+                $arrLP[$i]['item_type'] !== TOOL_LP_FINAL_ITEM
+            ) {
+                $arrHide[$arrLP[$i]['id']]['value'] = $arrLP[$i]['title'];
+            }
+        }
+
+        if (!$no_display_add) {
+            $item_type = isset($extra_info['item_type']) ? $extra_info['item_type'] : null;
+            $edit = isset($_GET['edit']) ? $_GET['edit'] : null;
+
+            if ($extra_info == 'new' || $item_type == TOOL_HIGHLIGHTED_DOCUMENT || $edit == 'true') {
+                if (!$no_display_edit_textarea) {
+                    $content = '';
+
+                    if (isset($_POST['content'])) {
+                        $content = stripslashes($_POST['content']);
+                    } elseif (is_array($extra_info)) {
+                        $content = $this->display_document($extra_info['path'], false, false);
+                    } elseif (is_numeric($extra_info)) {
+                        $content = $this->display_document($extra_info, false, false);
+                    }
+
+                    // A new document, it is in the root of the repository.
+                    if (is_array($extra_info) && $extra_info != 'new') {
+                    } else {
+                        $this->generate_lp_folder($_course);
+                    }
+
+                    if ($_GET['action'] == 'add_item') {
+                        $text = get_lang('LPCreateDocument');
+                    } else {
+                        $text = get_lang('SaveDocument');
+                    }
+
+                    $form->addTextarea('content_lp', get_lang('Content'), ['rows' => 20]);
+                    $form->addButtonSave($text, 'submit_button');
+                    $defaults['content_lp'] = $content;
+                }
+            } elseif (is_numeric($extra_info)) {
+                $form->addButtonSave(get_lang('SaveDocument'), 'submit_button');
+
+                $return = $this->display_document($extra_info, true, true, true);
+                $form->addElement('html', $return);
+            }
+        }
+
+        if (is_numeric($extra_info)) {
+            $form->addElement('hidden', 'path', $extra_info);
+        } elseif (is_array($extra_info)) {
+            $form->addElement('hidden', 'path', $extra_info['path']);
+        }
+
+        $form->addElement('hidden', 'type', TOOL_HIGHLIGHTED_DOCUMENT);
+        $form->addElement('hidden', 'post_time', time());
+        $form->setDefaults($defaults);
+
+        return $form->returnForm();
+    }
+
+    /**
+     * @param array  $courseInfo
+     * @param string $content
+     * @param string $title
+     * @param int    $parentId
+     *
+     * @return int
+     * @throws \Doctrine\ORM\ORMException
+     * @throws \Doctrine\ORM\OptimisticLockException
+     * @throws \Doctrine\ORM\TransactionRequiredException
+     */
+    public function createHighlightedDocument($courseInfo, $content = '', $title = '', $parentId = 0) {
+        $creatorId = api_get_user_id();
+        $sessionId = api_get_session_id();
+
+        // Generates folder
+        $result = $this->generate_lp_folder($courseInfo);
+        $dir = $result['dir'];
+
+        if (empty($parentId) || $parentId == '/') {
+            $postDir = isset($_POST['dir']) ? $_POST['dir'] : $dir;
+            $dir = isset($_GET['dir']) ? $_GET['dir'] : $postDir; // Please, do not modify this dirname formatting.
+
+            if ($parentId === '/') {
+                $dir = '/';
+            }
+
+            // Please, do not modify this dirname formatting.
+            if (strstr($dir, '..')) {
+                $dir = '/';
+            }
+
+            if (!empty($dir[0]) && $dir[0] == '.') {
+                $dir = substr($dir, 1);
+            }
+            if (!empty($dir[0]) && $dir[0] != '/') {
+                $dir = '/'.$dir;
+            }
+            if (isset($dir[strlen($dir) - 1]) && $dir[strlen($dir) - 1] != '/') {
+                $dir .= '/';
+            }
+        } else {
+            $parentInfo = DocumentManager::get_document_data_by_id(
+                $parentId,
+                $courseInfo['code']
+            );
+            if (!empty($parentInfo)) {
+                $dir = $parentInfo['path'].'/';
+            }
+        }
+
+        $filepath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document/'.$dir;
+
+        if (!is_dir($filepath)) {
+            $dir = '/';
+            $filepath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document/'.$dir;
+        }
+
+        $originalTitle = !empty($title) ? $title : $_POST['title'];
+
+        if (!empty($title)) {
+            $title = api_replace_dangerous_char(stripslashes($title));
+        } else {
+            $title = api_replace_dangerous_char(stripslashes($_POST['title']));
+        }
+
+        $title = disable_dangerous_file($title);
+        $filename = $title;
+        $content = !empty($content) ? $content : $_POST['content_lp'];
+        $tmpFileName = $filename;
+
+        $i = 0;
+        while (file_exists($filepath.$tmpFileName.'.html')) {
+            $tmpFileName = $filename.'_'.++$i;
+        }
+
+        $filename = $tmpFileName.'.html';
+        $content = stripslashes($content);
+
+        if (file_exists($filepath.$filename)) {
+            return 0;
+        }
+
+        $putContent = file_put_contents($filepath.$filename, $content);
+
+        if ($putContent === false) {
+            return 0;
+        }
+
+        $fileSize = filesize($filepath.$filename);
+        $saveFilePath = $dir.$filename;
+
+        $documentId = add_document(
+            $courseInfo,
+            $saveFilePath,
+            'file',
+            $fileSize,
+            $tmpFileName,
+            '',
+            0, //readonly
+            true,
+            null,
+            $sessionId,
+            $creatorId
+        );
+
+        if (!$documentId) {
+            return 0;
+        }
+
+        api_item_property_update(
+            $courseInfo,
+            TOOL_DOCUMENT,
+            $documentId,
+            'DocumentAdded',
+            $creatorId,
+            null,
+            null,
+            null,
+            null,
+            $sessionId
+        );
+
+        $newComment = isset($_POST['comment']) ? trim($_POST['comment']) : '';
+        $newTitle = $originalTitle;
+
+        if ($newComment || $newTitle) {
+            $em = Database::getManager();
+
+            /** @var CDocument $doc */
+            $doc = $em->find('ChamiloCourseBundle:CDocument', $documentId);
+
+            if ($newComment) {
+                $doc->setComment($newComment);
+            }
+
+            if ($newTitle) {
+                $doc->setTitle($newTitle);
+            }
+
+            $em->persist($doc);
+            $em->flush();
+        }
+
+        return $documentId;
+    }
+
     /**
      * Return HTML form to add/edit a link item.
      *
@@ -10016,6 +10493,7 @@ class learnpath
         $headers = [
             get_lang('Files'),
             get_lang('CreateTheDocument'),
+            get_lang('CreateHighlightedDocument'),
             get_lang('Upload'),
         ];
 
@@ -10087,9 +10565,10 @@ class learnpath
         $url = api_get_path(WEB_AJAX_PATH).'document.ajax.php?'.api_get_cidreq().'&a=upload_file&curdirpath=';
         $form->addMultipleUpload($url);
         $new = $this->display_document_form('add', 0);
+        $newHighlighted = $this->displayFrmHighlightedDocument('add');
         $tabs = Display::tabs(
             $headers,
-            [$documentTree, $new, $form->returnForm()],
+            [$documentTree, $new, $newHighlighted, $form->returnForm()],
             'subtab'
         );
 
@@ -12886,6 +13365,9 @@ EOD;
 
                 return $main_dir_path.'forum/viewthread.php?post='.$id.'&thread='.$myrow['thread_id'].'&forum='
                     .$myrow['forum_id'].'&lp=true&'.$extraParams;
+            case TOOL_HIGHLIGHTED_DOCUMENT:
+                return api_get_path(WEB_CODE_PATH).'lp/highlighted_document.php?&id='.$id.'&lp_id='.$learningPathId.'&'
+                    .$extraParams;
             case TOOL_DOCUMENT:
                 $document = $em
                     ->getRepository('ChamiloCourseBundle:CDocument')

+ 24 - 0
main/lp/lp_add_item.php

@@ -47,6 +47,30 @@ if ($learnPath->get_lp_session_id() != api_get_session_id()) {
 }
 
 $htmlHeadXtra[] = '<script>'.$learnPath->get_js_dropdown_array()."
+function load_cbo(id, previousId) {
+    if (!id) {
+        return false;
+    }
+    
+    previousId = previousId || 'previous';
+
+    var cbo = document.getElementById(previousId);
+    for (var i = cbo.length - 1; i > 0; i--) {
+        cbo.options[i] = null;
+    }
+
+    var k=0;
+    for (var i = 1; i <= child_name[id].length; i++){
+        var option = new Option(child_name[id][i - 1], child_value[id][i - 1]);
+        option.style.paddingLeft = '40px';
+        cbo.options[i] = option;
+        k = i;
+    }
+
+    cbo.options[k].selected = true;
+    $('#' + previousId).selectpicker('refresh');
+}
+
 $(function() {
     if ($('#previous')) {
         if('parent is'+$('#idParent').val()) {

+ 21 - 0
main/lp/lp_controller.php

@@ -451,6 +451,27 @@ switch ($action) {
                             $description,
                             $prerequisites
                         );
+                    } elseif ($_POST['type'] == TOOL_HIGHLIGHTED_DOCUMENT) {
+                        if (isset($_POST['path']) && $_GET['edit'] != 'true') {
+                            $document_id = $_POST['path'];
+                        } else {
+                            $document_id = $_SESSION['oLP']->createHighlightedDocument(
+                                $_course,
+                                $_POST['content_lp'],
+                                $_POST['title'],
+                                $directoryParentId
+                            );
+                        }
+
+                        $new_item_id = $_SESSION['oLP']->add_item(
+                            $parent,
+                            $previous,
+                            TOOL_HIGHLIGHTED_DOCUMENT,
+                            $document_id,
+                            $post_title,
+                            $description,
+                            $prerequisites
+                        );
                     } else {
                         // For all other item types than documents,
                         // load the item using the item type and path rather than its ID.

+ 11 - 12
main/lp/lp_nav.php

@@ -50,17 +50,16 @@ if ($myLP) {
     $progress_bar = $myLP->getProgressBar();
     $navigation_bar = $myLP->get_navigation_bar();
     $mediaplayer = $myLP->get_mediaplayer($lpItemId, $autostart);
+
+    if ($mediaplayer) {
+        echo $mediaplayer;
+        ?>
+        <script>
+            $(function() {
+                jQuery('video:not(.skip), audio:not(.skip)').mediaelementplayer();
+            });
+        </script>
+        <?php
+    }
 }
 session_write_close();
-?>
-<script>
-    $(document).ready(function() {
-        jQuery('video:not(.skip), audio:not(.skip)').mediaelementplayer({
-            success: function(player, node) {
-            }
-        });
-    });
-</script>
-<span>
-    <?php echo !empty($mediaplayer) ? $mediaplayer : '&nbsp;'; ?>
-</span>