Implemented folder management.

This commit is contained in:
2018-10-05 22:53:27 +03:00
parent 784d4deec8
commit c26732d101
19 changed files with 994 additions and 90 deletions

View File

@ -2,30 +2,38 @@
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Edit folder</h5>
<h5 id="folder_edit_dialog_title" class="modal-title">Edit folder</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form>
<div id="folder_edit_dialog_loading" class="modal-body">
<div class="loading-dual-ring"></div>
<div id="folder_edit_dialog_error"></div>
</div>
<form id="folder_edit_dialog_form" action="{% url 'ajax_edit_folder' %}" method="post">
<div class="modal-body">
{% csrf_token %}
<input type="hidden" id="folder_edit_dialog_id" name="id" value="#">
<div class="form-group row">
<label class="col-sm-4" for="folder_edit_dialog_name">Name</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="folder_edit_dialog_name" placeholder="Folder name">
<label class="col-sm-3" for="folder_edit_dialog_name">Name</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="folder_edit_dialog_name" name="name" placeholder="Folder name">
</div>
</div>
<div class="form-check row">
<input type="checkbox" class="form-check-input" id="exampleCheck1">
<label class="form-check-label" for="exampleCheck1">Check me out</label>
<div class="form-group row">
<label class="col-sm-3" for="folder_edit_dialog_parent">Parent folder</label>
<div class="col-sm-9">
<select class="form-control" id="folder_edit_dialog_parent" name="parent">
</select>
</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary">Save changes</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
<div class="modal-footer">
<button id="folder_edit_dialog_submit" type="submit" class="btn btn-primary">Submit</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</form>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,39 @@
<div id="subscription_edit_dialog" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 id="subscription_edit_dialog_title" class="modal-title">Edit subscription</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div id="subscription_edit_dialog_loading" class="modal-body">
<div class="loading-dual-ring"></div>
<div id="subscription_edit_dialog_error"></div>
</div>
<form id="subscription_edit_dialog_form" action="{% url 'ajax_edit_subscription' %}" method="post">
<div class="modal-body">
{% csrf_token %}
<input type="hidden" id="subscription_edit_dialog_id" name="id" value="#">
<div class="form-group row">
<label class="col-sm-3" for="subscription_edit_dialog_url">Link:</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="subscription_edit_dialog_name" name="name" placeholder="subscription name">
</div>
</div>
<div class="form-group row">
<label class="col-sm-3" for="subscription_edit_dialog_parent">Parent subscription</label>
<div class="col-sm-9">
<select class="form-control" id="subscription_edit_dialog_parent" name="parent">
</select>
</div>
</div>
</div>
<div class="modal-footer">
<button id="subscription_edit_dialog_submit" type="submit" class="btn btn-primary">Submit</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</form>
</div>
</div>
</div>

View File

@ -2,25 +2,38 @@
{% load static %}
{% block stylesheets %}
<link rel="stylesheet" href="{% static 'YtManagerApp/import/jstree/themes/default/style.min.css' %}" />
<link rel="stylesheet" href="{% static 'YtManagerApp/import/jstree/themes/default/style.min.css' %}" />
{% endblock %}
{% block scripts %}
<script src="{% static 'YtManagerApp/import/jstree/jstree.js' %}"></script>
<script src="{% static 'YtManagerApp/js/subtree.js' %}"></script>
<script src="{% static 'YtManagerApp/import/jstree/jstree.js' %}"></script>
<script>
{% include 'YtManagerApp/js/subscription_tree.js' %}
</script>
{% include 'YtManagerApp/controls/folder_edit_dialog.html' %}
{% endblock %}
{% block master %}
<div class="btn-toolbar" role="toolbar" aria-label="Subscriptions toolbar">
<div class="btn-group btn-group-sm mr-2" role="group">
<button type="button" class="btn btn-secondary">
<button type="button" class="btn btn-secondary" >
<i class="material-icons" aria-hidden="true">add</i>
</button>
<button type="button" class="btn btn-secondary">
<button id="btn_create_folder" type="button" class="btn btn-secondary">
<i class="material-icons" aria-hidden="true">create_new_folder</i>
</button>
</div>
<div class="btn-group btn-group-sm mr-2" role="group">
<button id="btn_edit_node" type="button" class="btn btn-secondary" >
<i class="material-icons" aria-hidden="true">edit</i>
</button>
<button id="btn_delete_node" type="button" class="btn btn-secondary" >
<i class="material-icons" aria-hidden="true">delete</i>
</button>
</div>
</div>
<div id="tree-wrapper">

View File

@ -0,0 +1,174 @@
function folderEditDialog_Show(isNew, editNode)
{
let dialog = $("#folder_edit_dialog");
dialog.find('#folder_edit_dialog_title').text(isNew ? "New folder" : "Edit folder");
dialog.find("#folder_edit_dialog_loading").show();
dialog.find("#folder_edit_dialog_error").hide();
dialog.find("#folder_edit_dialog_form").hide();
dialog.modal();
$.get("{% url 'ajax_get_folders' %}")
.done(function(folders)
{
// Populate list of folders
let selParent = dialog.find("#folder_edit_dialog_parent");
selParent.empty();
selParent.append(new Option('(None)', '#'));
let parentId = null;
if (!isNew) {
parentId = editNode.parent.replace('folder', '');
}
for (let folder of folders)
{
let o = new Option(folder.text, folder.id);
if (!isNew && folder.id.toString() === parentId.toString())
o.selected = true;
selParent.append(o);
}
// Show form
dialog.find("#folder_edit_dialog_loading").hide();
dialog.find("#folder_edit_dialog_form").show();
dialog.find("#folder_edit_dialog_submit").text(isNew ? "Create" : "Save");
if (isNew)
{
dialog.find("#folder_edit_dialog_id").val('#');
dialog.find("#folder_edit_dialog_name").val('');
}
if (!isNew)
{
idTrimmed = editNode.id.replace('folder', '');
dialog.find("#folder_edit_dialog_id").val(idTrimmed);
dialog.find("#folder_edit_dialog_name").val(editNode.text);
}
})
.fail(function() {
let msgError = dialog.find("#folder_edit_dialog_error");
msgError.show();
msgError.text("An error occurred!");
});
}
function folderEditDialog_ShowNew()
{
folderEditDialog_Show(true, null);
}
function folderEditDialog_Close()
{
$("#folder_edit_dialog").modal('hide');
}
function folderEditDialog_Submit(e)
{
let form = $(this);
let url = form.attr('action');
$.post(url, form.serialize())
.done(tree_Refresh);
folderEditDialog_Close();
e.preventDefault();
}
function treeNode_Edit()
{
let selectedNodes = $("#tree-wrapper").jstree('get_selected', true);
if (selectedNodes.length === 1)
{
let node = selectedNodes[0];
if (node.type === 'folder') {
folderEditDialog_Show(false, node);
}
else {
// TODO...
}
}
}
function treeNode_Delete()
{
let selectedNodes = $("#tree-wrapper").jstree('get_selected', true);
if (selectedNodes.length === 1)
{
let node = selectedNodes[0];
if (node.type === 'folder') {
let folderId = node.id.toString().replace('folder', '');
if (confirm('Are you sure you want to delete folder "' + node.text + '" and all its descendants?\nNote: the subscriptions won\'t be deleted, they will only be moved outside.'))
{
$.post("{% url 'ajax_delete_folder' 99999 %}".replace('99999', folderId), {
csrfmiddlewaretoken: '{{ csrf_token }}'
}).done(tree_Refresh);
}
}
else {
// TODO...
}
}
}
function tree_Initialize()
{
let treeWrapper = $("#tree-wrapper");
treeWrapper.jstree({
core : {
data : {
url : "{% url 'ajax_get_children' %}"
},
check_callback : tree_ValidateChange,
themes : {
dots : false
},
},
types : {
folder : {
icon : "material-icons material-folder"
},
sub : {
icon : "material-icons material-person",
max_depth : 0
}
},
plugins : [ "types", "wholerow", "dnd" ]
});
treeWrapper.on("changed.jstree", tree_OnSelectionChanged);
}
function tree_Refresh()
{
$("#tree-wrapper").jstree("refresh");
}
function tree_ValidateChange(operation, node, parent, position, more)
{
if (more.dnd)
{
// create_node, rename_node, delete_node, move_node and copy_node
if (operation === "copy_node" || operation === "move_node")
{
if (more.ref.type === "sub")
return false;
}
}
return true;
}
function tree_OnSelectionChanged(e, data)
{
node = data.instance.get_selected(true)[0];
}
$(document).ready(function ()
{
tree_Initialize();
$("#btn_create_folder").on("click", folderEditDialog_ShowNew);
$("#btn_edit_node").on("click", treeNode_Edit);
$("#btn_delete_node").on("click", treeNode_Delete);
$("#folder_edit_dialog_form").submit(folderEditDialog_Submit);
});