diff --git a/.idea/workspace.xml b/.idea/workspace.xml index dd56b21..557fc56 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -2,26 +2,11 @@ - - - + - - - - - - - - - - + - - - - - + - + - - - - - - - - - - + - - + + @@ -186,34 +162,22 @@ - + - - + + - + - - - - - - - - - - - - - - + + @@ -221,8 +185,8 @@ - - + + @@ -230,11 +194,32 @@ - - + + - - + + + + + + + + + + + + + + + + + + + + + + + @@ -243,19 +228,15 @@ - - - - - + - + - + @@ -268,12 +249,12 @@ - + - + @@ -295,10 +276,10 @@ @@ -356,8 +337,6 @@ @@ -589,6 +570,11 @@ + + + + + @@ -596,11 +582,6 @@ - - - - - - - - - - - - - - - - - - - @@ -954,59 +921,12 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + @@ -1044,16 +964,6 @@ - - - - - - - - - - @@ -1072,37 +982,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -1117,13 +997,6 @@ - - - - - - - @@ -1131,10 +1004,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + @@ -1152,65 +1107,40 @@ - + - - + + - + - - - - - - + + - + - - + + - - + - + - - + + - + - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/YtManagerApp/templates/YtManagerApp/index.html b/YtManagerApp/templates/YtManagerApp/index.html index 56c83f9..ad4980a 100644 --- a/YtManagerApp/templates/YtManagerApp/index.html +++ b/YtManagerApp/templates/YtManagerApp/index.html @@ -9,7 +9,7 @@ {% block scripts %} {% endblock %} diff --git a/YtManagerApp/templates/YtManagerApp/js/common.js b/YtManagerApp/templates/YtManagerApp/js/common.js index 1f51ea2..274e0a9 100644 --- a/YtManagerApp/templates/YtManagerApp/js/common.js +++ b/YtManagerApp/templates/YtManagerApp/js/common.js @@ -1,50 +1,3 @@ -class Dialog { - constructor(modalId) { - this.modal = $(modalId); - this.title = $(modalId + "_Title"); - this.form = $(modalId + "_Form"); - this.error = $(modalId + "_Error"); - this.loading = $(modalId + "_Loading"); - this.btnSubmit = $(modalId + "_Submit"); - this.setState('normal'); - } - - setTitle(value) { - this.title.text(value); - } - - setState(state) { - if (state === 'loading') { - this.loading.show(); - this.error.hide(); - this.form.hide(); - } - if (state === 'error') { - this.loading.hide(); - this.error.show(); - this.form.hide(); - } - if (state === 'normal') { - this.loading.hide(); - this.error.hide(); - this.form.show(); - } - } - - setError(text) { - this.error.text(text); - } - - showModal() { - this.modal.modal(); - } - - hideModal() { - this.modal.modal('hide'); - } -} - - class AjaxModal { constructor(url) @@ -100,7 +53,7 @@ class AjaxModal _submit(e) { let pThis = this; let url = this.form.attr('action'); - $.post(this.url, this.form.serialize()) + $.post(url, this.form.serialize()) .done(function(result) { pThis._submitDone(result); }) @@ -122,12 +75,22 @@ class AjaxModal // Clear old errors first this.form.find('.modal-field-error').remove(); + if (!result.hasOwnProperty('success')) { + this._submitInvalidResponse(); + return; + } + if (result.success) { this._hideModal(); if (this.submitCallback != null) this.submitCallback(); } else { + if (!result.hasOwnProperty('errors')) { + this._submitInvalidResponse(); + return; + } + for (let field in result.errors) if (result.errors.hasOwnProperty(field)) { @@ -160,11 +123,17 @@ class AjaxModal _submitFailed() { // Clear old errors first this.form.find('.modal-field-error').remove(); - this.form.find('.modal-body') .append(``); } + _submitInvalidResponse() { + // Clear old errors first + this.form.find('.modal-field-error').remove(); + this.form.find('.modal-body') + .append(``); + } + loadAndShow() { let pThis = this; diff --git a/YtManagerApp/templates/YtManagerApp/js/index.js b/YtManagerApp/templates/YtManagerApp/js/index.js new file mode 100644 index 0000000..2d70f67 --- /dev/null +++ b/YtManagerApp/templates/YtManagerApp/js/index.js @@ -0,0 +1,187 @@ +function treeNode_Edit() +{ + let selectedNodes = $("#tree-wrapper").jstree('get_selected', true); + if (selectedNodes.length === 1) + { + let node = selectedNodes[0]; + + if (node.type === 'folder') { + let id = node.id.replace('folder', ''); + let modal = new AjaxModal("{% url 'modal_update_folder' 98765 %}".replace('98765', id)); + modal.setSubmitCallback(tree_Refresh); + modal.loadAndShow(); + } + else { + let id = node.id.replace('sub', ''); + let modal = new AjaxModal("{% url 'modal_update_subscription' 98765 %}".replace('98765', id)); + modal.setSubmitCallback(tree_Refresh); + modal.loadAndShow(); + } + } +} + +function treeNode_Delete() +{ + let selectedNodes = $("#tree-wrapper").jstree('get_selected', true); + if (selectedNodes.length === 1) + { + let node = selectedNodes[0]; + + if (node.type === 'folder') { + let id = node.id.replace('folder', ''); + let modal = new AjaxModal("{% url 'modal_delete_folder' 98765 %}".replace('98765', id)); + modal.setSubmitCallback(tree_Refresh); + modal.loadAndShow(); + } + else { + let id = node.id.replace('sub', ''); + let modal = new AjaxModal("{% url 'modal_delete_subscription' 98765 %}".replace('98765', id)); + modal.setSubmitCallback(tree_Refresh); + modal.loadAndShow(); + } + } +} + +function tree_Initialize() +{ + let treeWrapper = $("#tree-wrapper"); + treeWrapper.jstree({ + core : { + data : { + url : "{% url 'ajax_get_tree' %}" + }, + check_callback : tree_ValidateChange, + themes : { + dots : false + }, + }, + types : { + folder : { + icon : "typcn typcn-folder" + }, + sub : { + icon : "typcn typcn-user", + 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) +{ + let filterForm = $('#form_video_filter'); + let filterForm_folderId = filterForm.find('#form_video_filter_folder_id'); + let filterForm_subId = filterForm.find('#form_video_filter_subscription_id'); + + let node = data.instance.get_selected(true)[0]; + + // Fill folder/sub fields + if (node == null) { + filterForm_folderId.val(''); + filterForm_subId.val(''); + } + else if (node.type === 'folder') { + let id = node.id.replace('folder', ''); + filterForm_folderId.val(id); + filterForm_subId.val(''); + } + else { + let id = node.id.replace('sub', ''); + filterForm_folderId.val(''); + filterForm_subId.val(id); + } + + videos_Reload(); +} + +function videos_Reload() +{ + videos_Submit.call($('#form_video_filter')); +} + +let videos_timeout = null; + +function videos_ReloadWithTimer() +{ + clearTimeout(videos_timeout); + videos_timeout = setTimeout(function() + { + videos_Submit.call($('#form_video_filter')); + videos_timeout = null; + }, 300); +} + +function videos_Submit(e) +{ + let loadingDiv = $('#videos-loading'); + loadingDiv.fadeIn(300); + + let form = $(this); + let url = form.attr('action'); + + $.post(url, form.serialize()) + .done(function(result) { + $("#videos-wrapper").html(result); + }) + .fail(function() { + $("#videos-wrapper").html('
An error occurred while retrieving the video list!
'); + }) + .always(function() { + loadingDiv.fadeOut(100); + }); + + if (e != null) + e.preventDefault(); +} + +/// +/// Initialization +/// +$(document).ready(function () +{ + tree_Initialize(); + + // Subscription toolbar + $("#btn_create_sub").on("click", function () { + let modal = new AjaxModal("{% url 'modal_create_subscription' %}"); + modal.setSubmitCallback(tree_Refresh); + modal.loadAndShow(); + }); + $("#btn_create_folder").on("click", function () { + let modal = new AjaxModal("{% url 'modal_create_folder' %}"); + modal.setSubmitCallback(tree_Refresh); + modal.loadAndShow(); + }); + $("#btn_edit_node").on("click", treeNode_Edit); + $("#btn_delete_node").on("click", treeNode_Delete); + + // Videos filters + let filters_form = $("#form_video_filter"); + filters_form.submit(videos_Submit); + filters_form.find('input[name=query]').on('change', videos_ReloadWithTimer); + filters_form.find('select[name=sort]').on('change', videos_ReloadWithTimer); + filters_form.find('select[name=show_watched]').on('change', videos_ReloadWithTimer); + filters_form.find('select[name=show_downloaded]').on('change', videos_ReloadWithTimer); +}); diff --git a/YtManagerApp/templates/YtManagerApp/js/subscription_tree.js b/YtManagerApp/templates/YtManagerApp/js/subscription_tree.js deleted file mode 100644 index 0fc69cd..0000000 --- a/YtManagerApp/templates/YtManagerApp/js/subscription_tree.js +++ /dev/null @@ -1,408 +0,0 @@ -class Dialog_old { - constructor(modalId) { - this.modal = $(modalId); - this.title = $(modalId + "_Title"); - this.form = $(modalId + "_Form"); - this.error = $(modalId + "_Error"); - this.loading = $(modalId + "_Loading"); - this.btnSubmit = $(modalId + "_Submit"); - this.setState('normal'); - } - - setTitle(value) { - this.title.text(value); - } - - setState(state) { - if (state === 'loading') { - this.loading.show(); - this.error.hide(); - this.form.hide(); - } - if (state === 'error') { - this.loading.hide(); - this.error.show(); - this.form.hide(); - } - if (state === 'normal') { - this.loading.hide(); - this.error.hide(); - this.form.show(); - } - } - - setError(text) { - this.error.text(text); - } - - showModal() { - this.modal.modal(); - } - - hideModal() { - this.modal.modal('hide'); - } -} - -class FolderEditDialog extends Dialog_old { - - constructor (modalId) { - super(modalId); - this.field_Id = $(modalId + "_Id"); - this.field_Name = $(modalId + "_Name"); - this.field_Parent = $(modalId + "_Parent"); - - let pThis = this; - this.form.submit(function(e) { - pThis.submit(e); - }) - } - - setParentFolderOptions(folders, selectedId) - { - // Populate list of folders - this.field_Parent.empty(); - this.field_Parent.append(new Option('(None)', '#')); - - for (let folder of folders) - { - let o = new Option(folder.text, folder.id); - if (selectedId != null && folder.id.toString() === selectedId.toString()) - o.selected = true; - - this.field_Parent.append(o); - } - } - - show (isNew, editNode) { - let pThis = this; - this.setTitle(isNew ? "New folder" : "Edit folder"); - this.setState('loading'); - this.showModal(); - - $.get("{% url 'ajax_get_folders' %}") - .done(function(folders) - { - let parentId = null; - if (!isNew) { - parentId = editNode.parent.replace('folder', ''); - } - - pThis.setParentFolderOptions(folders, parentId); - pThis.setState('normal'); - pThis.btnSubmit.text(isNew ? "Create" : "Save"); - - if (isNew) - { - pThis.field_Id.val('#'); - pThis.field_Name.val(''); - } - if (!isNew) - { - let idTrimmed = editNode.id.replace('folder', ''); - pThis.field_Id.val(idTrimmed); - pThis.field_Name.val(editNode.text); - } - }) - .fail(function() { - pThis.setState('error'); - pThis.setError('An error occurred!'); - }); - } - - showNew() { - this.show(true, null); - } - - showEdit(editNode) { - this.show(false, editNode); - } - - submit(e) { - let url = this.form.attr('action'); - - $.post(url, this.form.serialize()) - .done(tree_Refresh); - - this.hideModal(); - e.preventDefault(); - } -} - -class SubscriptionEditDialog extends Dialog_old { - - constructor (modalId) { - super(modalId); - this.field_Id = $(modalId + "_Id"); - this.field_Url = $(modalId + "_Url"); - this.field_Name = $(modalId + "_Name"); - this.field_Parent = $(modalId + "_Parent"); - - let pThis = this; - this.form.submit(function(e) { - pThis.submit(e); - }) - } - - setParentFolderOptions(folders, selectedId) - { - // Populate list of folders - this.field_Parent.empty(); - this.field_Parent.append(new Option('(None)', '#')); - - for (let folder of folders) - { - let o = new Option(folder.text, folder.id); - if (selectedId != null && folder.id.toString() === selectedId.toString()) - o.selected = true; - - this.field_Parent.append(o); - } - } - - show (isNew, editNode) { - let pThis = this; - this.setTitle(isNew ? "New subscription" : "Edit subscription"); - this.setState('loading'); - this.showModal(); - - $.get("{% url 'ajax_get_folders' %}") - .done(function(folders) - { - let parentId = null; - if (!isNew) { - parentId = editNode.parent.replace('folder', ''); - } - - pThis.setParentFolderOptions(folders, parentId); - pThis.setState('normal'); - pThis.btnSubmit.text(isNew ? "Create" : "Save"); - - if (isNew) - { - pThis.field_Id.val('#'); - pThis.field_Url.show(); - pThis.field_Url.val(''); - pThis.field_Name.hide(); - pThis.field_Name.val(''); - } - if (!isNew) - { - let idTrimmed = editNode.id.replace('sub', ''); - pThis.field_Id.val(idTrimmed); - pThis.field_Url.hide(); - pThis.field_Url.val(''); - pThis.field_Name.show(); - pThis.field_Name.val(editNode.text); - } - }) - .fail(function() { - pThis.setState('error'); - pThis.setError('An error occurred!'); - }); - } - - showNew() { - this.show(true, null); - } - - showEdit(editNode) { - this.show(false, editNode); - } - - submit(e) { - let url = this.form.attr('action'); - - $.post(url, this.form.serialize()) - .done(tree_Refresh); - - this.hideModal(); - 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') { - let id = node.id.replace('folder', ''); - let modal = new AjaxModal("{% url 'modal_update_folder' 98765 %}".replace('98765', id)); - modal.setSubmitCallback(tree_Refresh); - modal.loadAndShow(); - } - else { - let id = node.id.replace('sub', ''); - let modal = new AjaxModal("{% url 'modal_update_subscription' 98765 %}".replace('98765', id)); - modal.setSubmitCallback(tree_Refresh); - modal.loadAndShow(); - } - } -} - -function treeNode_Delete() -{ - let selectedNodes = $("#tree-wrapper").jstree('get_selected', true); - if (selectedNodes.length === 1) - { - let node = selectedNodes[0]; - - if (node.type === 'folder') { - let id = node.id.replace('folder', ''); - let modal = new AjaxModal("{% url 'modal_delete_folder' 98765 %}".replace('98765', id)); - modal.setSubmitCallback(tree_Refresh); - modal.loadAndShow(); - } - else { - let id = node.id.replace('sub', ''); - let modal = new AjaxModal("{% url 'modal_delete_subscription' 98765 %}".replace('98765', id)); - modal.setSubmitCallback(tree_Refresh); - modal.loadAndShow(); - } - } -} - -function tree_Initialize() -{ - let treeWrapper = $("#tree-wrapper"); - treeWrapper.jstree({ - core : { - data : { - url : "{% url 'ajax_get_tree' %}" - }, - check_callback : tree_ValidateChange, - themes : { - dots : false - }, - }, - types : { - folder : { - icon : "typcn typcn-folder" - }, - sub : { - icon : "typcn typcn-user", - 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) -{ - let filterForm = $('#form_video_filter'); - let filterForm_folderId = filterForm.find('#form_video_filter_folder_id'); - let filterForm_subId = filterForm.find('#form_video_filter_subscription_id'); - - let node = data.instance.get_selected(true)[0]; - - // Fill folder/sub fields - if (node == null) { - filterForm_folderId.val(''); - filterForm_subId.val(''); - } - else if (node.type === 'folder') { - let id = node.id.replace('folder', ''); - filterForm_folderId.val(id); - filterForm_subId.val(''); - } - else { - let id = node.id.replace('sub', ''); - filterForm_folderId.val(); - filterForm_subId.val(id); - } - - videos_Reload(); -} - - -function videos_Reload() -{ - let filterForm = $('#form_video_filter'); - let loadingDiv = $('#videos-loading'); - loadingDiv.fadeIn(300); - - // Perform query - $.post("{% url 'ajax_get_videos' %}", filterForm.serialize()) - .done(function (result) { - $("#videos-wrapper").html(result); - }) - .fail(function () { - $("#videos-wrapper").html('
An error occurred while retrieving the video list!
'); - }) - .always(function() { - loadingDiv.fadeOut(100); - }); -} - - -let videos_timeout = null; - -function videos_ReloadWithTimer() -{ - clearTimeout(videos_timeout); - videos_timeout = setTimeout(function() - { - videos_Reload(); - videos_timeout = null; - }, 500); -} - - - -/// -/// Globals -/// -let folderEditDialog = null; -let subscriptionEditDialog = null; - -/// -/// Initialization -/// -$(document).ready(function () -{ - tree_Initialize(); - - // folderEditDialog = new FolderEditDialog('#folderEditDialog'); - // subscriptionEditDialog = new SubscriptionEditDialog('#subscriptionEditDialog'); - // - $("#btn_create_sub").on("click", function () { - let modal = new AjaxModal("{% url 'modal_create_subscription' %}"); - modal.setSubmitCallback(tree_Refresh); - modal.loadAndShow(); - }); - $("#btn_create_folder").on("click", function () { - let modal = new AjaxModal("{% url 'modal_create_folder' %}"); - modal.setSubmitCallback(tree_Refresh); - modal.loadAndShow(); - }); - - // $("#btn_create_folder").on("click", function () { folderEditDialog.showNew(); }); - $("#btn_edit_node").on("click", treeNode_Edit); - $("#btn_delete_node").on("click", treeNode_Delete); -});