LP: Fix lp UI

pull/3890/head
Julio Montoya 5 years ago
parent 9aedf138d0
commit 89949824e5
  1. 7
      assets/js/app.js
  2. 3
      package.json
  3. 4
      public/main/inc/lib/display.lib.php
  4. 9
      public/main/inc/lib/document.lib.php
  5. 3
      public/main/inc/lib/formvalidator/FormValidator.class.php
  6. 8
      public/main/inc/lib/template.lib.php
  7. 4
      public/main/lp/LearnPathItemForm.php
  8. 424
      public/main/lp/learnpath.class.php
  9. 15
      public/main/lp/lp_add_item.php
  10. 114
      public/main/lp/lp_admin_view.php
  11. 32
      public/main/lp/lp_build.php
  12. 344
      public/main/lp/lp_controller.php
  13. 27
      public/main/lp/lp_edit_item.php
  14. 26
      public/main/lp/lp_edit_item_prereq.php
  15. 4
      public/main/lp/lp_view.php
  16. 1
      src/CoreBundle/Resources/views/Layout/layout_one_col.html.twig
  17. 14
      src/CoreBundle/Resources/views/Layout/layout_two_col.html.twig
  18. 18
      yarn.lock

@ -22,7 +22,7 @@ import 'select2/dist/css/select2.min.css';
//require('flatpickr');
//import('bootstrap-vue');
//import('bootstrap');
import('bootstrap');
require('webpack-jquery-ui');
require('webpack-jquery-ui/css');
@ -42,7 +42,10 @@ require('blueimp-load-image');
import('mediaelement');
require('multiselect-two-sides');
import 'jquery-sortablejs';
//import 'jquery-sortablejs';
import Sortable from 'sortablejs';
window.Sortable = Sortable;
import Swal from 'sweetalert2';
window.Swal = Swal;

@ -52,7 +52,6 @@
"html2canvas": "^1.0.0-rc.7",
"image-map-resizer": "^1.0.10",
"jquery": "^3.6.0",
"jquery-sortablejs": "^1.0.1",
"jquery-ui": "^1.12.1",
"jquery-ui-timepicker-addon": "^1.6.3",
"jquery-ui-touch-punch": "^0.2.3",
@ -107,7 +106,7 @@
"vue-router": "^4.0",
"vue-sidebar-menu": "^4.7.1",
"vue-toastification": "^2.0.0-rc.1",
"vuetify": "3.0.0-alpha.2",
"vuetify": "next",
"vuex": "^4.0.0",
"vuex-composition-helpers": "next",
"vuex-map-fields": "^1.4.0",

@ -2154,7 +2154,7 @@ class Display
id="'.$id.'"
class="btn btn-secondary dropdown-toggle"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
'.$title.'
'.$title.'
</button>
<div class="dropdown-menu aria-labelledby="'.$id.'" '.($alignToRight ? 'dropdown-menu-right' : '').'">';
foreach ($elements as $item) {
@ -2547,7 +2547,7 @@ class Display
$html = ' <div id="'.$id.'" class="q-card p-2 mb-4">';
$html .= ' <div class="flex justify-between '.$col.'">';
foreach ($contentList as $item) {
$html .= '<div class=" flex p-2 gap-2 ">'.$item.'</div>';
$html .= '<div class="flex p-2 gap-2 ">'.$item.'</div>';
}
$html .= '</div>';
$html .= '</div>';

@ -2910,7 +2910,7 @@ class DocumentManager
$options = [
'decorate' => true,
'rootOpen' => '<ul class="list-group lp_resource">',
'rootOpen' => '<ul id="doc_list" class="list-group lp_resource">',
'rootClose' => '</ul>',
//'childOpen' => '<li class="doc_resource lp_resource_element ">',
'childOpen' => function($child) {
@ -2928,7 +2928,7 @@ class DocumentManager
},
'childClose' => '</li>',
'nodeDecorator' => function ($node) use ($icon, $folderIcon) {
$link = '<div class="item_data">';
$link = '<div class="flex flex-row item_data">';
$file = $node['resourceFile'];
$extension = '';
if ($file) {
@ -2948,8 +2948,9 @@ class DocumentManager
data_type="document"
class="moved ui-sortable-handle link_with_id"
>';
$link .= $folder.'&nbsp;'.addslashes($node['title']);
$link .= $folder.'&nbsp;';
$link .= '</a>';
$link .= addslashes($node['title']);
$link .= '</div>';
return $link;
@ -6573,7 +6574,7 @@ This folder contains all sessions that have been opened in the chat. Although th
$return .= '<li class="doc_resource lp_resource_element '.$visibilityClass.' " data_id="'.$documentId.'" data_type="document" title="'.$my_file_title.'" >';
}
$return .= '<div class="item_data" style="margin-left:'.($num * 5).'px;margin-right:5px;">';
$return .= '<div class="flex flex-row item_data" style="margin-left:'.($num * 5).'px;margin-right:5px;">';
if ($add_move_button) {
$return .= '<a class="moved" href="#">';
$return .= Display::return_icon('move_everywhere.png', get_lang('Move'), [], ICON_SIZE_TINY);

@ -138,7 +138,7 @@ EOT;
{
return '<form{attributes}>
{content}
{hidden}
{hidden}
</form>';
}
@ -1215,7 +1215,6 @@ EOT;
public function returnForm()
{
$returnValue = '';
/** @var HTML_QuickForm_element $element */
foreach ($this->_elements as &$element) {
$element->setLayout($this->getLayout());

@ -221,6 +221,14 @@ class Template
$this->returnResponse($this->params, $template);
}
public function displayTwoColTemplate()
{
$this->loadLegacyParams();
$template = '@ChamiloCore/Layout/layout_two_col.html.twig';
$this->setVueParams($this->params);
$this->returnResponse($this->params, $template);
}
/**
* Displays an empty template.
*/

@ -134,9 +134,9 @@ class LearnPathItemForm
if (($document && $document->getResourceNode()->hasEditableTextContent()) || 'add' === $action) {
$renderer = $form->defaultRenderer();
$renderer->setElementTemplate('&nbsp;{label}{element}', 'content_lp');
$form->addElement('html', '<div class="editor-lp">');
$form->addHtml('<div class="editor-lp">');
$form->addHtmlEditor('content_lp', null, null, true, $editorConfig, true);
$form->addElement('html', '</div>');
$form->addHtml('</div>');
if ($document) {
$form->addHidden('document_id', $document->getIid());
$content = $lp->display_document(

@ -2775,7 +2775,7 @@ class learnpath
if ($isAllow && false == $hideIcons) {
if ($this->get_lp_session_id() == api_get_session_id()) {
$html .= '<div id="actions_lp" class="actions_lp"><hr>';
$html .= '<div class="btn-group">';
$html .= '<div class="flex flex-row justify-center">';
$html .= "<a
class='btn btn-sm btn-default'
href='lp_controller.php?".api_get_cidreq()."&action=build&lp_id=".$this->lp_id."&isStudentView=false'
@ -2785,7 +2785,7 @@ class learnpath
class='btn btn-sm btn-default'
href='lp_controller.php?".api_get_cidreq()."&action=add_item&type=step&lp_id=".$this->lp_id."&isStudentView=false'
target='_parent'>".
Display::returnFontAwesomeIcon('pencil').get_lang('Edit')."</a>";
Display::returnFontAwesomeIcon('pencil-alt').get_lang('Edit')."</a>";
$html .= '<a
class="btn btn-sm btn-default"
href="lp_controller.php?'.api_get_cidreq()."&action=edit&lp_id=".$this->lp_id.'&isStudentView=false">'.
@ -4966,17 +4966,25 @@ class learnpath
*/
public function overview()
{
exit;
$return = '';
$update_audio = $_GET['updateaudio'] ?? null;
// we need to start a form when we want to update all the mp3 files
if ('true' == $update_audio) {
$return .= '<form action="'.api_get_self().'?'.api_get_cidreq().'&updateaudio='.Security::remove_XSS($_GET['updateaudio']).'&action='.Security::remove_XSS($_GET['action']).'&lp_id='.$_SESSION['oLP']->lp_id.'" method="post" enctype="multipart/form-data" name="updatemp3" id="updatemp3">';
$return .= '<form action="'.api_get_self().'?'.api_get_cidreq().'&updateaudio='.Security::remove_XSS(
$_GET['updateaudio']
).'&action='.Security::remove_XSS(
$_GET['action']
).'&lp_id='.$_SESSION['oLP']->lp_id.'" method="post" enctype="multipart/form-data" name="updatemp3" id="updatemp3">';
}
$return .= '<div id="message"></div>';
if (0 == count($this->items)) {
$return .= Display::return_message(get_lang('You should add some items to your learning path, otherwise you won\'t be able to attach audio files to them'), 'normal');
$return .= Display::return_message(
get_lang(
'You should add some items to your learning path, otherwise you won\'t be able to attach audio files to them'
),
'normal'
);
} else {
$return_audio = '<table class="table table-hover table-striped data_table">';
$return_audio .= '<tr>';
@ -4985,15 +4993,15 @@ class learnpath
$return_audio .= '</tr>';
if ('true' != $update_audio) {
$return .= '<div class="col-md-12">';
/*$return .= '<div class="col-md-12">';
$return .= self::return_new_tree($update_audio);
$return .= '</div>';
$return .= '</div>';*/
$return .= Display::div(
Display::url(get_lang('Save'), '#', ['id' => 'listSubmit', 'class' => 'btn btn-primary']),
['style' => 'float:left; margin-top:15px;width:100%']
);
} else {
$return_audio .= self::return_new_tree($update_audio);
//$return_audio .= self::return_new_tree($update_audio);
$return .= $return_audio.'</table>';
}
@ -5489,11 +5497,360 @@ class learnpath
public function showBuildSideBar($updateAudio = false, $dropElementHere = false, $type = null)
{
$sureToDelete = trim(get_lang('AreYouSureToDeleteJS'));
$ajax_url = api_get_path(WEB_AJAX_PATH).'lp.ajax.php?lp_id='.$this->get_id().'&'.api_get_cidreq();
$content = "
$content = '
<script>
/*
Script to manipulate Learning Path items with Drag and drop
*/
var newOrderData = "";
function buildLPtree(in_elem, in_parent_id) {
var item_tag = in_elem.get(0).tagName;
var item_id = in_elem.attr("id");
//var parent_id = item_id;
in_elem.children("li").each(function () {
let itemId = $(this).attr("id");
if (itemId && itemId != "undefined") {
newOrderData += itemId + "|" + in_parent_id+"^";
$(this).find("ul").each(function () {
buildLPtree($(this), itemId);
});
}
});
}
$(function() {
$(".lp_resource6").sortable({
items: ".lp_resource_element ",
handle: ".moved", //only the class "moved"
cursor: "move",
connectWith: "#lp_item_list",
placeholder: "ui-state-highlight", //defines the yellow highlight
start: function(event, ui) {
$(ui.item).css("width", "350px");
$(ui.item).find(".item_data").attr("style", "");
},
stop: function(event, ui) {
$(ui.item).css("width", "100%");
}
});
$(".li_container2 .order_items").click(function(e) {
var dir = $(this).data("dir");
var itemId = $(this).data("id");
var jItems = $("#lp_item_list li.li_container");
var jItem = $("#"+ itemId);
var index = jItems.index(jItem);
var total = jItems.length;
switch (dir) {
case "up":
if (index != 0 && jItems[index - 1]) {
/*var subItems = $(jItems[index - 1]).find("li.sub_item");
if (subItems.length >= 0) {
index = index - 1;
}*/
var subItems = $(jItems[index - 1]).find("li.sub_item");
var parentClass = $(jItems[index - 1]).parent().parent().attr("class");
var parentId = $(jItems[index]).parent().parent().attr("id");
var myParentId = $(jItems[index - 1]).parent().parent().attr("id");
// We are brothers!
if (parentId == myParentId) {
if (subItems.length > 0) {
var lastItem = $(jItems[index - 1]).find("li.sub_item");
parentIndex = jItems.index(lastItem);
jItem.detach().insertAfter(lastItem);
} else {
jItem.detach().insertBefore(jItems[index - 1]);
}
break;
}
if (parentClass == "record li_container") {
// previous is a chapter
var lastItem = $(jItems[index - 1]).parent().parent().find("li.li_container").last();
parentIndex = jItems.index(lastItem);
jItem.detach().insertAfter(jItems[parentIndex]);
} else {
jItem.detach().insertBefore(jItems[index - 1]);
}
}
break;
case "down":
if (index != total - 1) {
const originIndex = index;
// The element is a chapter with items
var subItems = jItem.find("li.li_container");
if (subItems.length > 0) {
index = subItems.length + index;
}
var subItems = $(jItems[index + 1]).find("li.sub_item");
// This is an element entering in a chapter
if (subItems.length > 0) {
// Check if im a child
var parentClass = jItem.parent().parent().attr("class");
if (parentClass == "record li_container") {
// Parent position
var parentIndex = jItems.index(jItem.parent().parent());
jItem.detach().insertAfter(jItems[parentIndex]);
} else {
jItem.detach().insertAfter(subItems);
}
break;
}
var currentSubItems = $(jItems[index]).parent().find("li.sub_item");
var parentId = $(jItems[originIndex]).parent().parent().attr("id");
var myParentId = $(jItems[index + 1]).parent().parent().attr("id");
// We are brothers!
if (parentId == myParentId) {
if ((index + 1) < total) {
jItem.detach().insertAfter(jItems[index + 1]);
}
break;
}
if (currentSubItems.length > 0) {
var parentIndex = jItems.index(jItem.parent().parent());
if (parentIndex >= 0) {
jItem.detach().insertAfter(jItems[parentIndex]);
break;
}
//jItem.detach().insertAfter($(jItems[index]).parent().parent());
}
//var lastItem = $(jItems[index + 1]).parent().parent().find("li.li_container").last();
if (subItems.length > 0) {
index = originIndex;
}
if ((index + 1) < total) {
jItem.detach().insertAfter(jItems[index + 1]);
}
}
break;
}
buildLPtree($("#lp_item_list"), 0);
var order = "new_order="+ newOrderData + "&a=update_lp_item_order";
$.get(
"'.$ajax_url.'",
order,
function(reponse) {
$("#message").html(reponse);
order = "";
newOrderData = "";
}
);
});
function refreshTree() {
var params = "&a=get_lp_item_tree";
$.get(
"'.$ajax_url.'",
params,
function(result) {
serialized = [];
$("#lp_item_list").html(result);
}
);
}
const nestedQuery = ".nested-sortable";
const identifier = "id";
const root = document.getElementById("lp_item_list");
/*function serialize(sortable) {
var serialized = [];
var children = [].slice.call(sortable.children);
for (var i in children) {
var nested = children[i].querySelector(nestedQuery);
serialized.push({
id: children[i].dataset[identifier],
children: nested ? serialize(nested) : []
});
}
return serialized;
}*/
var serialized = [];
function serialize(sortable) {
var children = [].slice.call(sortable.children);
for (var i in children) {
var nested = children[i].querySelector(nestedQuery);
var parentId = $(children[i]).parent().parent().attr("id");
//console.log("---");
var id = children[i].dataset[identifier];
if (typeof id === "undefined") {
return;
}
//console.log(id); console.log(parentId);
serialized.push({
id: children[i].dataset[identifier],
parent_id: parentId
});
if (nested) {
serialize(nested);
}
}
return serialized;
}
let tree = document.getElementById("lp_item_list");
Sortable.create(tree, {
group: "nested",
put: ["nested-sortable", ".lp_resource", ".nested-source"],
animation: 150,
//fallbackOnBody: true,
swapThreshold: 0.65,
dataIdAttr: "data-id",
store: {
set: function (sortable) {
var order = sortable.toArray();
console.log(order);
}
},
onEnd: function(evt) {
console.log("onEnd");
let list = serialize(root);
let order = "&a=update_lp_item_order&new_order=" + JSON.stringify(list);
$.get(
"'.$ajax_url.'",
order,
function(reponse) {
$("#message").html(reponse);
refreshTree();
}
);
},
});
let docs = document.getElementById("doc_list");
Sortable.create(docs, {
//$(".lp_resource").sortable({
group: "nested",
put: ["nested-sortable"],
filter: ".disable_drag",
animation: 150,
fallbackOnBody: true,
swapThreshold: 0.65,
dataIdAttr: "data-id",
onRemove: function(evt) {
console.log("onRemove");
var itemEl = evt.item;
var newIndex = evt.newIndex;
var id = $(itemEl).attr("id");
var parent_id = $(itemEl).parent().parent().attr("id");
var type = $(itemEl).find(".link_with_id").attr("data_type");
var title = $(itemEl).find(".link_with_id").text();
let previousId = 0;
if (0 !== newIndex) {
previousId = $(itemEl).prev().attr("id");
}
var params = {
"a": "add_lp_item",
"id": id,
"parent_id": parent_id,
"previous_id": previousId,
"type": type,
"title" : title
};
console.log(params);
$.ajax({
type: "GET",
url: "'.$ajax_url.'",
data: params,
success: function(itemId) {
$(itemEl).attr("id", itemId);
$(itemEl).attr("data-id", itemId);
let list = serialize(root);
let listInString = JSON.stringify(list);
if (typeof listInString === "undefined") {
listInString = "";
}
let order = "&a=update_lp_item_order&new_order=" + listInString;
$.get(
"'.$ajax_url.'",
order,
function(reponse) {
$("#message").html(reponse);
refreshTree();
}
);
//$("#lp_item_list").html(data);
}
});
},
});
$("#lp_item_list2").sortable({
items: "li",
handle: ".moved", //only the class "moved"
cursor: "move",
placeholder: "ui-state-highlight", //defines the yellow highlight
update: function(event, ui) {
buildLPtree($("#lp_item_list"), 0);
var order = "new_order="+ newOrderData + "&a=update_lp_item_order";
$.get(
"'.$ajax_url.'",
order,
function(reponse) {
$("#message").html(reponse);
order = "";
newOrderData = "";
}
);
},
receive: function(event, ui) {
var item = $(ui.item).find(".link_with_id");
var id = item.attr("data_id");
var type = item.attr("data_type");
var title = item.attr("title");
processReceive = true;
//console.log(ui.item.parent().parent().attr("id"));
if (ui.item.parent()[0]) {
//var parent_id = $(ui.item.parent()[0]).attr("id");
var previous_id = $(ui.item.prev()).attr("id");
var parent_id = ui.item.parent().parent().parent().attr("id");
if (parent_id == "undefined") {
parent_id = 0;
}
console.log(parent_id);
var params = {
"a": "add_lp_item",
"id": id,
"parent_id": parent_id,
"previous_id": previous_id,
"type": type,
"title" : title
};
console.log(params);
$.ajax({
type: "GET",
url: "'.$ajax_url.'",
data: params,
success: function(data) {
//$("#scorm-list .card-body").html(data);
$("#lp_item_list").html(data);
}
});
}
}
});
processReceive = false;
});
</script>';
$content .= "
<script>
function confirmation(name) {
if (confirm('$sureToDelete' + name)) {
return true;
@ -5501,8 +5858,6 @@ class learnpath
return false;
}
}
function refreshTree() {
var params = '&a=get_lp_item_tree';
$.get(
@ -5573,7 +5928,6 @@ class learnpath
}
</script>";
$content .= '<div id="lp_sidebar" class="col-md-4">';
$content .= $this->return_new_tree($updateAudio, $dropElementHere);
$documentId = isset($_GET['path_item']) ? (int) $_GET['path_item'] : 0;
@ -5588,12 +5942,10 @@ class learnpath
// Show the template list.
if (('document' === $type || 'step' === $type) && !isset($_GET['file'])) {
// Show the template list.
$content .= '<div id="frmModel" class="scrollbar-inner lp-add-item">';
$content .= '</div>';
$content .= '<div id="frmModel" class="scrollbar-inner lp-add-item"></div>';
}
$content .= '</div>';
echo $content;
return $content;
}
/**
@ -5700,7 +6052,7 @@ class learnpath
},
'childOpen' => function($child) {
$id = $child['iid'];
return '<li id="'.$id.'" data-id="'.$id.'" class="list-group-item nested-'.$child['lvl'].'">';
return '<li id="'.$id.'" data-id="'.$id.'" class=" flex flex-col list-group-item nested-'.$child['lvl'].'">';
},
'childClose' => '',
'nodeDecorator' => function ($node) use ($mainUrl, $previewImage, $upIcon, $downIcon) {
@ -5754,8 +6106,8 @@ class learnpath
['class' => 'btn btn-default']
);
$editIcon = '';
$editIcon .= '<a
//$editIcon = '';
$editIcon = '<a
href="'.$mainUrl.'&action=edit_item&view=build&id='.$itemId.'&lp_id='.$lpId.'&path_item='.$node['path'].'"
class="btn btn-default"
>';
@ -5818,11 +6170,11 @@ class learnpath
//return $title. $extra;
return
// '<div class="item_data">'.
$moveIcon.' '.$icon.' '.
$title.
$extra.
"<div class='flex flex-row'> $moveIcon $icon <div>$title </div></div>
$extra
$buttons
//.'</div>'
"
;
},
];
@ -6005,7 +6357,7 @@ class learnpath
if ((false === strpos($request, 'build') &&
false === strpos($request, 'add_item')) ||
in_array($action, ['add_audio'])
in_array($action, ['add_audio'], true)
) {
$actionsLeft .= Display::url(
Display::return_icon(
@ -6420,11 +6772,9 @@ class learnpath
public function display_edit_item($lpItem, $excludeExtraFields = [])
{
$return = '';
if (empty($lpItem)) {
return '';
}
$item_id = $lpItem->getIid();
$itemType = $lpItem->getItemType();
$path = $lpItem->getPath();
@ -6434,15 +6784,9 @@ class learnpath
case 'sco':
if (isset($_GET['view']) && 'build' === $_GET['view']) {
$return .= $this->displayItemMenu($lpItem);
$return .= $this->display_item_form(
$lpItem,
'edit'
);
$return .= $this->display_item_form($lpItem, 'edit');
} else {
$return .= $this->display_item_form(
$lpItem,
'edit_item'
);
$return .= $this->display_item_form($lpItem, 'edit_item');
}
break;
case TOOL_LP_FINAL_ITEM:
@ -6541,14 +6885,14 @@ class learnpath
Display::return_icon('certificate.png', get_lang('Certificate'), [], $size),
];
echo Display::return_message(
$content = Display::return_message(
get_lang('Click on the [Learner view] button to see your learning path'),
'normal'
);
$section = $this->displayNewSectionForm();
$selected = isset($_REQUEST['lp_build_selected']) ? (int) $_REQUEST['lp_build_selected'] : 0;
echo Display::tabs(
$content .= Display::tabs(
$headers,
[
$documents,
@ -6565,7 +6909,7 @@ class learnpath
$selected
);
return true;
return $content;
}
/**
@ -7103,8 +7447,6 @@ class learnpath
}
}*/
$return .= '</div>';
if (!empty($audio_player)) {
$return .= $audio_player;
}
@ -7689,7 +8031,7 @@ class learnpath
$form->addButtonSearch(get_lang('Search'));
$return = $form->returnForm();
$return .= '<ul class=" list-group lp_resource">';
$return .= '<ul id="doc_list" class=" list-group lp_resource">';
$return .= '<li class="list-group-item lp_resource_element disable_drag">';
$return .= Display::return_icon('new_exercice.png');
$return .= '<a

@ -127,12 +127,12 @@ if ('add_item' === $action && 'document' === $type) {
$show_learn_path = true;
$lp_theme_css = $learnPath->get_theme();
Display::display_header(null, 'Path');
echo $learnPath->build_action_menu();
echo '<div class="row">';
echo $learnPath->showBuildSideBar(null, true, $type);
echo '<div id="doc_form" class="col-md-8">';
$learnPath->displayResources();
$tpl = new Template();
$tpl->assign('actions', $learnPath->build_action_menu(true));
$tpl->assign('left', $learnPath->showBuildSideBar(null, true, $type));
$tpl->assign('right', $learnPath->displayResources());
$tpl->displayTwoColTemplate();
/*
switch ($type) {
@ -173,7 +173,4 @@ switch ($type) {
case 'step':
break;
}*/
echo '</div>';
echo '</div>';
Display::display_footer();

@ -147,116 +147,21 @@ if (isset($_POST['save_audio'])) {
exit;
}
Display::display_header(null, 'Path');
$suredel = trim(get_lang('Are you sure to delete'));
exit;
?>
<script>
var newOrderData= "";
//source code found in http://www.swartzfager.org/blog/dspNestedList.cfm
$(function() {
<?php
if (!isset($_REQUEST['updateaudio'])) {
?>
$("#lp_item_list").sortable({
items: "li",
handle: ".moved", //only the class "moved"
cursor: "move",
placeholder: "ui-state-highlight" //defines the yellow highlight
});
$("#listSubmit").click(function () {
//Disable the submit button to prevent a double-click
$(this).attr("disabled","disabled");
//Initialize the variable that will contain the data to submit to the form
newOrderData= "";
//All direct descendants of the lp_item_list will have a parentId of 0
var parentId= 0;
//Walk through the direct descendants of the lp_item_list <ul>
$("#lp_item_list").children().each(function () {
/*Only process elements with an id attribute (in order to skip the blank,
unmovable <li> elements.*/
if ($(this).attr("id")) {
console.log($(this).attr("id"));
//console.log($(this).attr("id"));
/*Build a string of data with the child's ID and parent ID,
using the "|" as a delimiter between the two IDs and the "^"
as a record delimiter (these delimiters were chosen in case the data
involved includes more common delimiters like commas within the content)
*/
newOrderData= newOrderData + $(this).attr("id") + "|" + "0" + "^";
//Determine if this child is a containter
if ($(this).is(".li_container")) {
//Process the child elements of the container
processChildren($(this).attr("id"));
}
}
}); //end of lp_item_list children loop
//Write the newOrderData string out to the listResults form element
//$("#listResults").val(newOrderData);
var order = "new_order="+ newOrderData + "&a=update_lp_item_order";
$.post("<?php echo api_get_path(WEB_AJAX_PATH); ?>lp.ajax.php", order, function(reponse) {
$("#message").html(reponse);
});
setTimeout(function() {
$("#message").html('');
}, 3000);
return false;
}); //end of lp_item_list event assignment
<?php
} ?>
function processChildren(parentId) {
//Loop through the children of the UL element defined by the parentId
var ulParentID= "UL_" + parentId;
$("#" + ulParentID).children().each(function () {
/*Only process elements with an id attribute (in order to skip the blank,
unmovable <li> elements.*/
if ($(this).attr("id")) {
/*Build a string of data with the child's ID and parent ID,
using the "|" as a delimiter between the two IDs and the "^"
as a record delimiter (these delimiters were chosen in case the data
involved includes more common delimiters like commas within the content)
*/
newOrderData= newOrderData + $(this).attr("id") + "|" + parentId + "^";
//Determine if this child is a containter
if ($(this).is(".container")) {
//Process the child elements of the container
processChildren($(this).attr("id"));
}
}
}); //end of children loop
} //end of processChildren function
});
</script>
<?php
echo $learnPath->build_action_menu();
echo '<div class="row">';
echo $learnPath->showBuildSideBar(null, true);
echo '<div class="col-md-8">';
$right = '';
switch ($_GET['action']) {
case 'edit_item':
if (isset($is_success) && true === $is_success) {
echo Display::return_message(
$right .= Display::return_message(
get_lang('The learning object has been edited'),
'confirm'
);
} else {
echo $learnPath->display_edit_item($lpItem);
$right .= $learnPath->display_edit_item($lpItem);
}
break;
case 'delete_item':
if (isset($is_success) && true === $is_success) {
echo Display::return_message(
$right .= Display::return_message(
get_lang('The learning object has been deleted'),
'confirm'
);
@ -265,10 +170,11 @@ switch ($_GET['action']) {
}
if (!empty($_GET['updateaudio'])) {
// list of items to add audio files
echo $learnPath->overview();
$right .= $learnPath->overview();
}
echo '</div>';
echo '</div>';
Display::display_footer();
$tpl = new Template(get_lang('Prerequisites'));
$tpl->assign('actions', $learnPath->build_action_menu(true));
$tpl->assign('left', $learnPath->showBuildSideBar());
$tpl->assign('right', $right);
$tpl->displayTwoColTemplate();

@ -1,4 +1,5 @@
<?php
/* For licensing terms, see /license.txt */
use ChamiloSession as Session;
@ -47,36 +48,39 @@ $interbreadcrumb[] = ['url' => '#', 'name' => $learnPath->getNameNoTags()];
// Theme calls.
$lp_theme_css = $learnPath->get_theme();
$show_learn_path = true;
Display::display_header('', 'Path');
echo $learnPath->build_action_menu();
echo '<div class="row">';
echo $learnPath->showBuildSideBar();
echo '<div class="flex flex-row">';
$rightColumn = $learnPath->showBuildSideBar();
if (isset($is_success) && true === $is_success) {
echo Display::return_message(get_lang('The learning object has been removed'), 'confirmation');
$rightColumn .= Display::return_message(get_lang('The learning object has been removed'), 'confirmation');
} else {
if ($is_new) {
echo Display::return_message(get_lang('Course added'), 'normal', false);
$rightColumn .= Display::return_message(get_lang('Course added'), 'normal', false);
}
echo Display::page_subheader(get_lang('Welcome to the Chamilo course authoring tool !'));
echo '<ul id="lp_overview" class="thumbnails">';
echo show_block(
$rightColumn .= Display::page_subheader(get_lang('Welcome to the Chamilo course authoring tool !'));
$rightColumn .= '<ul id="lp_overview" class="thumbnails">';
$rightColumn .= show_block(
'lp_controller.php?'.api_get_cidreq().'&action=add_item&type=step&lp_id='.$learnPath->get_id(),
get_lang("Add learning object or activity"),
get_lang('Add learning object or activityComment'),
'tools.png'
);
echo show_block(
$rightColumn .= show_block(
'lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.$learnPath->get_id(),
get_lang("Ranking"),
get_lang('RankingComment'),
'view.png'
);
echo '</ul>';
$rightColumn .= '</ul>';
}
echo '</div>';
echo '</div>';
echo 'ju';
exit;
$tpl = new Template();
$tpl->assign('left', $learnPath->build_action_menu());
$tpl->assign('right', $rightColumn);
echo $tpl->fetch('@ChamiloCore/Layout/layout_two_col.html.twig');
function show_block($link, $title, $subtitle, $icon)
{

@ -52,350 +52,6 @@ if ($showGlossary) {
$ajax_url = api_get_path(WEB_AJAX_PATH).'lp.ajax.php?lp_id='.$lpId.'&'.api_get_cidreq();
$listUrl = api_get_self().'?action=list&'.api_get_cidreq();
$htmlHeadXtra[] = '
<script>
function setFocus(){
$("#idTitle").focus();
}
$(window).on("load", function () {
setFocus();
});
/*
Script to manipulate Learning Path items with Drag and drop
*/
var newOrderData = "";
function buildLPtree(in_elem, in_parent_id) {
var item_tag = in_elem.get(0).tagName;
var item_id = in_elem.attr("id");
//var parent_id = item_id;
in_elem.children("li").each(function () {
let itemId = $(this).attr("id");
if (itemId && itemId != "undefined") {
newOrderData += itemId + "|" + in_parent_id+"^";
$(this).find("ul").each(function () {
buildLPtree($(this), itemId);
});
}
});
}
$(function() {
$(".lp_resource2").sortable({
items: ".lp_resource_element ",
handle: ".moved", //only the class "moved"
cursor: "move",
connectWith: "#lp_item_list",
placeholder: "ui-state-highlight", //defines the yellow highlight
start: function(event, ui) {
$(ui.item).css("width", "350px");
$(ui.item).find(".item_data").attr("style", "");
},
stop: function(event, ui) {
$(ui.item).css("width", "100%");
}
});
$(".li_container2 .order_items").click(function(e) {
var dir = $(this).data("dir");
var itemId = $(this).data("id");
var jItems = $("#lp_item_list li.li_container");
var jItem = $("#"+ itemId);
var index = jItems.index(jItem);
var total = jItems.length;
switch (dir) {
case "up":
if (index != 0 && jItems[index - 1]) {
/*var subItems = $(jItems[index - 1]).find("li.sub_item");
if (subItems.length >= 0) {
index = index - 1;
}*/
var subItems = $(jItems[index - 1]).find("li.sub_item");
var parentClass = $(jItems[index - 1]).parent().parent().attr("class");
var parentId = $(jItems[index]).parent().parent().attr("id");
var myParentId = $(jItems[index - 1]).parent().parent().attr("id");
// We are brothers!
if (parentId == myParentId) {
if (subItems.length > 0) {
var lastItem = $(jItems[index - 1]).find("li.sub_item");
parentIndex = jItems.index(lastItem);
jItem.detach().insertAfter(lastItem);
} else {
jItem.detach().insertBefore(jItems[index - 1]);
}
break;
}
if (parentClass == "record li_container") {
// previous is a chapter
var lastItem = $(jItems[index - 1]).parent().parent().find("li.li_container").last();
parentIndex = jItems.index(lastItem);
jItem.detach().insertAfter(jItems[parentIndex]);
} else {
jItem.detach().insertBefore(jItems[index - 1]);
}
}
break;
case "down":
if (index != total - 1) {
const originIndex = index;
// The element is a chapter with items
var subItems = jItem.find("li.li_container");
if (subItems.length > 0) {
index = subItems.length + index;
}
var subItems = $(jItems[index + 1]).find("li.sub_item");
// This is an element entering in a chapter
if (subItems.length > 0) {
// Check if im a child
var parentClass = jItem.parent().parent().attr("class");
if (parentClass == "record li_container") {
// Parent position
var parentIndex = jItems.index(jItem.parent().parent());
jItem.detach().insertAfter(jItems[parentIndex]);
} else {
jItem.detach().insertAfter(subItems);
}
break;
}
var currentSubItems = $(jItems[index]).parent().find("li.sub_item");
var parentId = $(jItems[originIndex]).parent().parent().attr("id");
var myParentId = $(jItems[index + 1]).parent().parent().attr("id");
// We are brothers!
if (parentId == myParentId) {
if ((index + 1) < total) {
jItem.detach().insertAfter(jItems[index + 1]);
}
break;
}
if (currentSubItems.length > 0) {
var parentIndex = jItems.index(jItem.parent().parent());
if (parentIndex >= 0) {
jItem.detach().insertAfter(jItems[parentIndex]);
break;
}
//jItem.detach().insertAfter($(jItems[index]).parent().parent());
}
//var lastItem = $(jItems[index + 1]).parent().parent().find("li.li_container").last();
if (subItems.length > 0) {
index = originIndex;
}
if ((index + 1) < total) {
jItem.detach().insertAfter(jItems[index + 1]);
}
}
break;
}
buildLPtree($("#lp_item_list"), 0);
var order = "new_order="+ newOrderData + "&a=update_lp_item_order";
$.get(
"'.$ajax_url.'",
order,
function(reponse) {
$("#message").html(reponse);
order = "";
newOrderData = "";
}
);
});
function refreshTree() {
var params = "&a=get_lp_item_tree";
$.get(
"'.$ajax_url.'",
params,
function(result) {
serialized = [];
$("#lp_item_list").html(result);
}
);
}
const nestedQuery = ".nested-sortable";
const identifier = "id";
const root = document.getElementById("lp_item_list");
/*function serialize(sortable) {
var serialized = [];
var children = [].slice.call(sortable.children);
for (var i in children) {
var nested = children[i].querySelector(nestedQuery);
serialized.push({
id: children[i].dataset[identifier],
children: nested ? serialize(nested) : []
});
}
return serialized;
}*/
var serialized = [];
function serialize(sortable) {
var children = [].slice.call(sortable.children);
for (var i in children) {
var nested = children[i].querySelector(nestedQuery);
var parentId = $(children[i]).parent().parent().attr("id");
//console.log("---");
var id = children[i].dataset[identifier];
if (typeof id === "undefined") {
return;
}
//console.log(id); console.log(parentId);
serialized.push({
id: children[i].dataset[identifier],
parent_id: parentId
});
if (nested) {
serialize(nested);
}
}
return serialized;
}
$(".nested-sortable").sortable({
group: "nested",
put: ["nested-sortable", ".lp_resource", ".nested-source"],
animation: 150,
fallbackOnBody: true,
swapThreshold: 0.65,
dataIdAttr: "data-id",
onEnd: function(evt) {
let list = serialize(root);
let order = "&a=update_lp_item_order&new_order=" + JSON.stringify(list);
$.get(
"'.$ajax_url.'",
order,
function(reponse) {
$("#message").html(reponse);
refreshTree();
}
);
},
});
$(".lp_resource").sortable({
group: "nested",
put: ["nested-sortable"],
filter: ".disable_drag",
animation: 150,
fallbackOnBody: true,
swapThreshold: 0.65,
dataIdAttr: "data-id",
onRemove: function(evt) {
var itemEl = evt.item;
var newIndex = evt.newIndex;
var id = $(itemEl).attr("id");
var parent_id = $(itemEl).parent().parent().attr("id");
var type = $(itemEl).find(".link_with_id").attr("data_type");
var title = $(itemEl).find(".link_with_id").text();
let previousId = 0;
if (0 !== newIndex) {
previousId = $(itemEl).prev().attr("id");
}
var params = {
"a": "add_lp_item",
"id": id,
"parent_id": parent_id,
"previous_id": previousId,
"type": type,
"title" : title
};
console.log(params);
$.ajax({
type: "GET",
url: "'.$ajax_url.'",
data: params,
success: function(itemId) {
$(itemEl).attr("id", itemId);
$(itemEl).attr("data-id", itemId);
let list = serialize(root);
let listInString = JSON.stringify(list);
if (typeof listInString === "undefined") {
listInString = "";
}
let order = "&a=update_lp_item_order&new_order=" + listInString;
$.get(
"'.$ajax_url.'",
order,
function(reponse) {
$("#message").html(reponse);
refreshTree();
}
);
//$("#lp_item_list").html(data);
}
});
},
});
$("#lp_item_list2").sortable({
items: "li",
handle: ".moved", //only the class "moved"
cursor: "move",
placeholder: "ui-state-highlight", //defines the yellow highlight
update: function(event, ui) {
buildLPtree($("#lp_item_list"), 0);
var order = "new_order="+ newOrderData + "&a=update_lp_item_order";
$.get(
"'.$ajax_url.'",
order,
function(reponse) {
$("#message").html(reponse);
order = "";
newOrderData = "";
}
);
},
receive: function(event, ui) {
var item = $(ui.item).find(".link_with_id");
var id = item.attr("data_id");
var type = item.attr("data_type");
var title = item.attr("title");
processReceive = true;
//console.log(ui.item.parent().parent().attr("id"));
if (ui.item.parent()[0]) {
//var parent_id = $(ui.item.parent()[0]).attr("id");
var previous_id = $(ui.item.prev()).attr("id");
var parent_id = ui.item.parent().parent().parent().attr("id");
if (parent_id == "undefined") {
parent_id = 0;
}
console.log(parent_id);
var params = {
"a": "add_lp_item",
"id": id,
"parent_id": parent_id,
"previous_id": previous_id,
"type": type,
"title" : title
};
console.log(params);
$.ajax({
type: "GET",
url: "'.$ajax_url.'",
data: params,
success: function(data) {
//$("#scorm-list .card-body").html(data);
$("#lp_item_list").html(data);
}
});
}
}
});
processReceive = false;
});
</script>';
$lpfound = false;
$myrefresh = 0;
$myrefresh_id = 0;

@ -71,11 +71,7 @@ $interbreadcrumb[] = [
$show_learn_path = true;
$lp_theme_css = $learnPath->get_theme();
Display::display_header(get_lang('Edit'), 'Path');
echo $learnPath->build_action_menu();
echo '<div class="row">';
echo $learnPath->showBuildSideBar();
echo '<div id="doc_form" class="col-md-8">';
$excludeExtraFields = [
'authors',
'authorlp',
@ -86,21 +82,24 @@ if (api_is_platform_admin()) {
// Only admins can edit this items
$excludeExtraFields = [];
}
$right = '';
if (isset($is_success) && true === $is_success) {
$msg = '<div class="lp_message" style="margin-bottom:10px;">';
$msg .= 'The item has been edited.';
$msg .= '</div>';
echo $learnPath->display_item($lpItem, $msg);
$right = '<div class="lp_message" style="margin-bottom:10px;">';
$right .= 'The item has been edited.';
$right .= '</div>';
$right .= $learnPath->display_item($lpItem, $msg);
} else {
echo $learnPath->display_edit_item($lpItem, $excludeExtraFields);
$right .= $learnPath->display_edit_item($lpItem, $excludeExtraFields);
$finalItem = Session::read('finalItem');
if ($finalItem) {
echo '<script>$("#frmModel").remove()</script>';
$right .= '<script>$("#frmModel").remove()</script>';
}
Session::erase('finalItem');
}
echo '</div>';
echo '</div>';
Display::display_footer();
$tpl = new Template();
$tpl->assign('actions', $learnPath->build_action_menu(true));
$tpl->assign('left', $learnPath->showBuildSideBar());
$tpl->assign('right', $right);
$tpl->displayTwoColTemplate();

@ -55,20 +55,18 @@ $interbreadcrumb[] = [
'name' => get_lang('Add learning object or activity'),
];
Display::display_header(get_lang('Prerequisites'), 'Path');
echo $lp->build_action_menu();
echo '<div class="row">';
echo $lp->showBuildSideBar();
echo '<div class="col-md-8">';
echo '<div class="prerequisites">';
$right = '';
if (isset($is_success) && true == $is_success) {
echo $lp->displayItemMenu($lpItem);
echo Display::return_message(get_lang('Prerequisites to the current learning object have been added.'));
$right .= $lp->displayItemMenu($lpItem);
$right .= Display::return_message(get_lang('Prerequisites to the current learning object have been added.'));
} else {
echo $lp->displayItemMenu($lpItem);
echo $lp->display_item_prerequisites_form($lpItem);
$right .= $lp->displayItemMenu($lpItem);
$right .= $lp->display_item_prerequisites_form($lpItem);
}
echo '</div>';
echo '</div>';
Display::display_footer();
$tpl = new Template(get_lang('Prerequisites'));
$tpl->assign('actions', $lp->build_action_menu(true));
$tpl->assign('left', $lp->showBuildSideBar());
$tpl->assign('right', $right);
$tpl->displayTwoColTemplate();

@ -129,7 +129,7 @@ $allowLpItemTip = false === api_get_configuration_value('hide_accessibility_labe
if ($allowLpItemTip) {
$htmlHeadXtra[] = '<script>
$(function() {
$(".scorm_item_normal").qtip({
/*$(".scorm_item_normal").qtip({
content: {
text: function(event, api) {
var item = $(this);
@ -155,7 +155,7 @@ if ($allowLpItemTip) {
return textToShow;
}
}
});
});*/
});
</script>';
}

@ -13,7 +13,6 @@
{{~ js }}
{% endfor %}
{% endautoescape %}
{% endif %}
{%- autoescape false %}

@ -0,0 +1,14 @@
{% extends '@ChamiloCore/Layout/layout_one_col.html.twig' %}
{%- block content %}
{%- autoescape false %}
<div class="flex flex-row">
<div class="w-2/5">
{{ left }}
</div>
<div class="w-3/5">
{{ right }}
</div>
</div>
{% endautoescape %}
{% endblock -%}

@ -5874,7 +5874,6 @@ __metadata:
html2canvas: ^1.0.0-rc.7
image-map-resizer: ^1.0.10
jquery: ^3.6.0
jquery-sortablejs: ^1.0.1
jquery-ui: ^1.12.1
jquery-ui-timepicker-addon: ^1.6.3
jquery-ui-touch-punch: ^0.2.3
@ -5937,7 +5936,7 @@ __metadata:
vue-router: ^4.0
vue-sidebar-menu: ^4.7.1
vue-toastification: ^2.0.0-rc.1
vuetify: 3.0.0-alpha.2
vuetify: next
vuex: ^4.0.0
vuex-composition-helpers: next
vuex-map-fields: ^1.4.0
@ -11456,13 +11455,6 @@ fsevents@~2.3.1:
languageName: node
linkType: hard
"jquery-sortablejs@npm:^1.0.1":
version: 1.6.1
resolution: "jquery-sortablejs@npm:1.6.1"
checksum: c8634b36e7c59c1a301c0f43a726d9969028aec15a2f28dd14ac5d729570b7ede7e2a7661fd794815b473fdc886c81e92a0347096fbf0356f9ce951f5f7ab8d0
languageName: node
linkType: hard
"jquery-ui-timepicker-addon@npm:^1.6.3":
version: 1.6.3
resolution: "jquery-ui-timepicker-addon@npm:1.6.3"
@ -18874,12 +18866,12 @@ typescript@~4.1.5:
languageName: node
linkType: hard
"vuetify@npm:3.0.0-alpha.2":
version: 3.0.0-alpha.2
resolution: "vuetify@npm:3.0.0-alpha.2"
"vuetify@npm:next":
version: 3.0.0-alpha.3
resolution: "vuetify@npm:3.0.0-alpha.3"
peerDependencies:
vue: ^3.0.7
checksum: bf5251fb233fb6b38639dff960128f234ab7b022f6ab66d002bf0d110f6e9a834a057a53a15de29122abe8f4b7a155cc8daa922c1219db73fe7282d6c057b6ac
checksum: abdd5c26d9b16e52f74aa284141c88edf1c3e5c73bad87dbb7cbd969c6e0d097376eef6be5eaf147c72d7e4ce8a03d111bd75f397e2096a19c41c496a7769844
languageName: node
linkType: hard

Loading…
Cancel
Save