Implemented folder management.
This commit is contained in:
parent
784d4deec8
commit
c26732d101
7
.idea/misc.xml
Normal file
7
.idea/misc.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JavaScriptSettings">
|
||||||
|
<option name="languageLevel" value="ES6" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/youtube-channel-manager.iml" filepath="$PROJECT_DIR$/.idea/youtube-channel-manager.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
51
.idea/watcherTasks.xml
Normal file
51
.idea/watcherTasks.xml
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectTasksOptions">
|
||||||
|
<TaskOptions isEnabled="true">
|
||||||
|
<option name="arguments" value="$FileName$ $FileNameWithoutExtension$.css --source-map" />
|
||||||
|
<option name="checkSyntaxErrors" value="true" />
|
||||||
|
<option name="description" />
|
||||||
|
<option name="exitCodeBehavior" value="ERROR" />
|
||||||
|
<option name="fileExtension" value="less" />
|
||||||
|
<option name="immediateSync" value="true" />
|
||||||
|
<option name="name" value="Less" />
|
||||||
|
<option name="output" value="$FileNameWithoutExtension$.css:$FileNameWithoutExtension$.css.map" />
|
||||||
|
<option name="outputFilters">
|
||||||
|
<array>
|
||||||
|
<FilterInfo>
|
||||||
|
<option name="description" value="" />
|
||||||
|
<option name="name" value="" />
|
||||||
|
<option name="regExp" value="$MESSAGE$\Q in \E$FILE_PATH$\Q on line \E$LINE$\Q, column \E$COLUMN$" />
|
||||||
|
</FilterInfo>
|
||||||
|
</array>
|
||||||
|
</option>
|
||||||
|
<option name="outputFromStdout" value="false" />
|
||||||
|
<option name="program" value="$USER_HOME$/AppData/Roaming/npm/lessc.cmd" />
|
||||||
|
<option name="runOnExternalChanges" value="true" />
|
||||||
|
<option name="scopeName" value="Project Files" />
|
||||||
|
<option name="trackOnlyRoot" value="true" />
|
||||||
|
<option name="workingDir" value="$FileDir$" />
|
||||||
|
<envs />
|
||||||
|
</TaskOptions>
|
||||||
|
<TaskOptions isEnabled="true">
|
||||||
|
<option name="arguments" value="--no-cache --update $FileName$:$FileNameWithoutExtension$.css" />
|
||||||
|
<option name="checkSyntaxErrors" value="true" />
|
||||||
|
<option name="description" />
|
||||||
|
<option name="exitCodeBehavior" value="ERROR" />
|
||||||
|
<option name="fileExtension" value="scss" />
|
||||||
|
<option name="immediateSync" value="true" />
|
||||||
|
<option name="name" value="SCSS" />
|
||||||
|
<option name="output" value="$FileNameWithoutExtension$.css:$FileNameWithoutExtension$.css.map" />
|
||||||
|
<option name="outputFilters">
|
||||||
|
<array />
|
||||||
|
</option>
|
||||||
|
<option name="outputFromStdout" value="false" />
|
||||||
|
<option name="program" value="scss" />
|
||||||
|
<option name="runOnExternalChanges" value="true" />
|
||||||
|
<option name="scopeName" value="Project Files" />
|
||||||
|
<option name="trackOnlyRoot" value="true" />
|
||||||
|
<option name="workingDir" value="$FileDir$" />
|
||||||
|
<envs />
|
||||||
|
</TaskOptions>
|
||||||
|
</component>
|
||||||
|
</project>
|
463
.idea/workspace.xml
Normal file
463
.idea/workspace.xml
Normal file
@ -0,0 +1,463 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ChangeListManager">
|
||||||
|
<list default="true" id="245751b6-c863-4572-8723-8499964fe105" name="Default Changelist" comment="">
|
||||||
|
<change afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/.idea/watcherTasks.xml" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/YtManagerApp/management.py" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/YtManagerApp/migrations/0004_auto_20181005_1626.py" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/YtManagerApp/static/YtManagerApp/css/style.css.map" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/YtManagerApp/static/YtManagerApp/css/style.scss" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/YtManagerApp/templates/YtManagerApp/controls/subscription_edit_dialog.html" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/YtManagerApp/templates/YtManagerApp/js/subscription_tree.js" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/YtManager/urls.py" beforeDir="false" afterPath="$PROJECT_DIR$/YtManager/urls.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/YtManagerApp/static/YtManagerApp/css/style.css" beforeDir="false" afterPath="$PROJECT_DIR$/YtManagerApp/static/YtManagerApp/css/style.css" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/YtManagerApp/static/YtManagerApp/import/jstree/jstree.js" beforeDir="false" afterPath="$PROJECT_DIR$/YtManagerApp/static/YtManagerApp/import/jstree/jstree.js" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/YtManagerApp/static/YtManagerApp/js/subtree.js" beforeDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/YtManagerApp/templates/YtManagerApp/controls/folder_edit_dialog.html" beforeDir="false" afterPath="$PROJECT_DIR$/YtManagerApp/templates/YtManagerApp/controls/folder_edit_dialog.html" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/YtManagerApp/templates/YtManagerApp/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/YtManagerApp/templates/YtManagerApp/index.html" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/YtManagerApp/views.py" beforeDir="false" afterPath="$PROJECT_DIR$/YtManagerApp/views.py" afterDir="false" />
|
||||||
|
</list>
|
||||||
|
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||||
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
|
</component>
|
||||||
|
<component name="DjangoConsoleOptions" custom-start-script="import sys; print('Python %s on %s' % (sys.version, sys.platform)) import django; print('Django %s' % django.get_version()) sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS]) if 'setup' in dir(django): django.setup() import django_manage_shell; django_manage_shell.run(PROJECT_ROOT)">
|
||||||
|
<option name="myCustomStartScript" value="import sys; print('Python %s on %s' % (sys.version, sys.platform)) import django; print('Django %s' % django.get_version()) sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS]) if 'setup' in dir(django): django.setup() import django_manage_shell; django_manage_shell.run(PROJECT_ROOT)" />
|
||||||
|
</component>
|
||||||
|
<component name="FUSProjectUsageTrigger">
|
||||||
|
<session id="1684258556">
|
||||||
|
<usages-collector id="statistics.lifecycle.project">
|
||||||
|
<counts>
|
||||||
|
<entry key="project.closed" value="1" />
|
||||||
|
<entry key="project.open.time.11" value="1" />
|
||||||
|
<entry key="project.open.time.3" value="1" />
|
||||||
|
<entry key="project.opened" value="2" />
|
||||||
|
</counts>
|
||||||
|
</usages-collector>
|
||||||
|
<usages-collector id="statistics.file.extensions.edit">
|
||||||
|
<counts>
|
||||||
|
<entry key="css" value="40" />
|
||||||
|
<entry key="html" value="620" />
|
||||||
|
<entry key="js" value="2858" />
|
||||||
|
<entry key="less" value="38" />
|
||||||
|
<entry key="py" value="1710" />
|
||||||
|
<entry key="py@youtube-channel-manager" value="19" />
|
||||||
|
<entry key="scss" value="26" />
|
||||||
|
</counts>
|
||||||
|
</usages-collector>
|
||||||
|
<usages-collector id="statistics.file.types.edit">
|
||||||
|
<counts>
|
||||||
|
<entry key="CSS" value="40" />
|
||||||
|
<entry key="CommandLine" value="19" />
|
||||||
|
<entry key="HTML" value="620" />
|
||||||
|
<entry key="JavaScript" value="2858" />
|
||||||
|
<entry key="Less" value="38" />
|
||||||
|
<entry key="Python" value="1710" />
|
||||||
|
<entry key="SCSS" value="26" />
|
||||||
|
</counts>
|
||||||
|
</usages-collector>
|
||||||
|
<usages-collector id="statistics.file.extensions.open">
|
||||||
|
<counts>
|
||||||
|
<entry key="css" value="1" />
|
||||||
|
<entry key="html" value="8" />
|
||||||
|
<entry key="js" value="5" />
|
||||||
|
<entry key="less" value="1" />
|
||||||
|
<entry key="py" value="7" />
|
||||||
|
<entry key="scss" value="3" />
|
||||||
|
</counts>
|
||||||
|
</usages-collector>
|
||||||
|
<usages-collector id="statistics.file.types.open">
|
||||||
|
<counts>
|
||||||
|
<entry key="CSS" value="1" />
|
||||||
|
<entry key="HTML" value="8" />
|
||||||
|
<entry key="JavaScript" value="5" />
|
||||||
|
<entry key="Less" value="1" />
|
||||||
|
<entry key="Python" value="7" />
|
||||||
|
<entry key="SCSS" value="3" />
|
||||||
|
</counts>
|
||||||
|
</usages-collector>
|
||||||
|
</session>
|
||||||
|
</component>
|
||||||
|
<component name="FileEditorManager">
|
||||||
|
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
|
||||||
|
<file pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/YtManagerApp/views.py">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="334">
|
||||||
|
<caret line="62" lean-forward="true" selection-start-line="62" selection-end-line="62" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#35#0" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/YtManagerApp/management.py">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="504">
|
||||||
|
<caret line="42" column="11" selection-start-line="42" selection-start-column="11" selection-end-line="42" selection-end-column="11" />
|
||||||
|
<folding>
|
||||||
|
<marker date="1538766618853" expanded="true" signature="90:91" ph="..." />
|
||||||
|
<marker date="1538766618853" expanded="true" signature="642:651" ph="..." />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/YtManagerApp/templates/YtManagerApp/js/subscription_tree.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="1700">
|
||||||
|
<caret line="100" column="186" selection-start-line="100" selection-start-column="186" selection-end-line="100" selection-end-column="186" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file pinned="false" current-in-tab="true">
|
||||||
|
<entry file="file://$PROJECT_DIR$/YtManagerApp/templates/YtManagerApp/controls/subscription_edit_dialog.html">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="357">
|
||||||
|
<caret line="21" column="30" lean-forward="true" selection-start-line="21" selection-start-column="30" selection-end-line="21" selection-end-column="30" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#433#440#1#HTML" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
</leaf>
|
||||||
|
</component>
|
||||||
|
<component name="FileTemplateManagerImpl">
|
||||||
|
<option name="RECENT_TEMPLATES">
|
||||||
|
<list>
|
||||||
|
<option value="SCSS File" />
|
||||||
|
<option value="Python Script" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="FindInProjectRecents">
|
||||||
|
<findStrings>
|
||||||
|
<find>lds</find>
|
||||||
|
<find>get_selected</find>
|
||||||
|
<find>url</find>
|
||||||
|
<find>delete_fo</find>
|
||||||
|
<find>folder</find>
|
||||||
|
</findStrings>
|
||||||
|
<replaceStrings>
|
||||||
|
<replace>loading</replace>
|
||||||
|
<replace />
|
||||||
|
<replace>subscription</replace>
|
||||||
|
<replace>subscription</replace>
|
||||||
|
</replaceStrings>
|
||||||
|
</component>
|
||||||
|
<component name="Git.Settings">
|
||||||
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||||
|
</component>
|
||||||
|
<component name="IdeDocumentHistory">
|
||||||
|
<option name="CHANGED_PATHS">
|
||||||
|
<list>
|
||||||
|
<option value="$PROJECT_DIR$/YtManagerApp/static/YtManagerApp/css/style.css" />
|
||||||
|
<option value="$PROJECT_DIR$/YtManagerApp/static/YtManagerApp/css/style.less" />
|
||||||
|
<option value="$PROJECT_DIR$/YtManagerApp/templates/YtManagerApp/main_default.html" />
|
||||||
|
<option value="$PROJECT_DIR$/YtManagerApp/static/YtManagerApp/import/jstree/jstree.min.js" />
|
||||||
|
<option value="$PROJECT_DIR$/YtManagerApp/static/YtManagerApp/css/style.scss" />
|
||||||
|
<option value="$PROJECT_DIR$/YtManagerApp/templates/YtManagerApp/controls/folder_edit_dialog.html" />
|
||||||
|
<option value="$PROJECT_DIR$/YtManagerApp/views.py" />
|
||||||
|
<option value="$PROJECT_DIR$/YtManagerApp/management.py" />
|
||||||
|
<option value="$PROJECT_DIR$/YtManagerApp/static/YtManagerApp/js/subscription_tree.js" />
|
||||||
|
<option value="$PROJECT_DIR$/YtManagerApp/templates/YtManagerApp/index.html" />
|
||||||
|
<option value="$PROJECT_DIR$/YtManager/urls.py" />
|
||||||
|
<option value="$PROJECT_DIR$/YtManagerApp/templates/YtManagerApp/js/subscription_tree.js" />
|
||||||
|
<option value="$PROJECT_DIR$/YtManagerApp/templates/YtManagerApp/controls/subscription_edit_dialog.html" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
|
||||||
|
<component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
|
||||||
|
<component name="JsGulpfileManager">
|
||||||
|
<detection-done>true</detection-done>
|
||||||
|
<sorting>DEFINITION_ORDER</sorting>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectFrameBounds" extendedState="6">
|
||||||
|
<option name="x" value="-8" />
|
||||||
|
<option name="y" value="1" />
|
||||||
|
<option name="width" value="1400" />
|
||||||
|
<option name="height" value="1000" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectView">
|
||||||
|
<navigator proportions="" version="1">
|
||||||
|
<foldersAlwaysOnTop value="true" />
|
||||||
|
</navigator>
|
||||||
|
<panes>
|
||||||
|
<pane id="ProjectPane">
|
||||||
|
<subPane>
|
||||||
|
<expand>
|
||||||
|
<path>
|
||||||
|
<item name="youtube-channel-manager" type="b2602c69:ProjectViewProjectNode" />
|
||||||
|
<item name="youtube-channel-manager" type="462c0819:PsiDirectoryNode" />
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<item name="youtube-channel-manager" type="b2602c69:ProjectViewProjectNode" />
|
||||||
|
<item name="youtube-channel-manager" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="YtManager" type="462c0819:PsiDirectoryNode" />
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<item name="youtube-channel-manager" type="b2602c69:ProjectViewProjectNode" />
|
||||||
|
<item name="youtube-channel-manager" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="YtManagerApp" type="462c0819:PsiDirectoryNode" />
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<item name="youtube-channel-manager" type="b2602c69:ProjectViewProjectNode" />
|
||||||
|
<item name="youtube-channel-manager" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="YtManagerApp" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="static" type="462c0819:PsiDirectoryNode" />
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<item name="youtube-channel-manager" type="b2602c69:ProjectViewProjectNode" />
|
||||||
|
<item name="youtube-channel-manager" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="YtManagerApp" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="static" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="YtManagerApp" type="462c0819:PsiDirectoryNode" />
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<item name="youtube-channel-manager" type="b2602c69:ProjectViewProjectNode" />
|
||||||
|
<item name="youtube-channel-manager" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="YtManagerApp" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="templates" type="462c0819:PsiDirectoryNode" />
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<item name="youtube-channel-manager" type="b2602c69:ProjectViewProjectNode" />
|
||||||
|
<item name="youtube-channel-manager" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="YtManagerApp" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="templates" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="YtManagerApp" type="462c0819:PsiDirectoryNode" />
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<item name="youtube-channel-manager" type="b2602c69:ProjectViewProjectNode" />
|
||||||
|
<item name="youtube-channel-manager" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="YtManagerApp" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="templates" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="YtManagerApp" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="controls" type="462c0819:PsiDirectoryNode" />
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<item name="youtube-channel-manager" type="b2602c69:ProjectViewProjectNode" />
|
||||||
|
<item name="youtube-channel-manager" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="YtManagerApp" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="templates" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="YtManagerApp" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="js" type="462c0819:PsiDirectoryNode" />
|
||||||
|
</path>
|
||||||
|
</expand>
|
||||||
|
<select />
|
||||||
|
</subPane>
|
||||||
|
</pane>
|
||||||
|
<pane id="Scope" />
|
||||||
|
</panes>
|
||||||
|
</component>
|
||||||
|
<component name="PropertiesComponent">
|
||||||
|
<property name="SearchEverywhereHistoryKey" value="	FILE	file://D:/Dev/youtube-channel-manager/YtManagerApp/views.py" />
|
||||||
|
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||||
|
<property name="last_opened_file_path" value="$USER_HOME$/AppData/Roaming/npm/lessc.cmd" />
|
||||||
|
<property name="list.type.of.created.stylesheet" value="SCSS" />
|
||||||
|
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
|
||||||
|
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
|
||||||
|
<property name="settings.editor.selected.configurable" value="preferences.sourceCode" />
|
||||||
|
</component>
|
||||||
|
<component name="RecentsManager">
|
||||||
|
<key name="CopyFile.RECENT_KEYS">
|
||||||
|
<recent name="D:\Dev\youtube-channel-manager\YtManagerApp\templates\YtManagerApp\controls" />
|
||||||
|
</key>
|
||||||
|
<key name="MoveFile.RECENT_KEYS">
|
||||||
|
<recent name="D:\Dev\youtube-channel-manager\YtManagerApp\templates\YtManagerApp" />
|
||||||
|
</key>
|
||||||
|
</component>
|
||||||
|
<component name="RunDashboard">
|
||||||
|
<option name="ruleStates">
|
||||||
|
<list>
|
||||||
|
<RuleState>
|
||||||
|
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
|
||||||
|
</RuleState>
|
||||||
|
<RuleState>
|
||||||
|
<option name="name" value="StatusDashboardGroupingRule" />
|
||||||
|
</RuleState>
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="RunManager">
|
||||||
|
<configuration name="youtube-channel-manager" type="Python.DjangoServer" factoryName="Django server">
|
||||||
|
<module name="youtube-channel-manager" />
|
||||||
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="PARENT_ENVS" value="true" />
|
||||||
|
<envs>
|
||||||
|
<env name="PYTHONUNBUFFERED" value="1" />
|
||||||
|
<env name="DJANGO_SETTINGS_MODULE" value="YtManager.settings" />
|
||||||
|
</envs>
|
||||||
|
<option name="SDK_HOME" value="" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="" />
|
||||||
|
<option name="IS_MODULE_SDK" value="false" />
|
||||||
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||||
|
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||||
|
<option name="launchJavascriptDebuger" value="false" />
|
||||||
|
<option name="port" value="8000" />
|
||||||
|
<option name="host" value="" />
|
||||||
|
<option name="additionalOptions" value="" />
|
||||||
|
<option name="browserUrl" value="" />
|
||||||
|
<option name="runTestServer" value="false" />
|
||||||
|
<option name="runNoReload" value="false" />
|
||||||
|
<option name="useCustomRunCommand" value="false" />
|
||||||
|
<option name="customRunCommand" value="" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
|
<component name="SvnConfiguration">
|
||||||
|
<configuration />
|
||||||
|
</component>
|
||||||
|
<component name="TaskManager">
|
||||||
|
<task active="true" id="Default" summary="Default task">
|
||||||
|
<changelist id="245751b6-c863-4572-8723-8499964fe105" name="Default Changelist" comment="" />
|
||||||
|
<created>1538745535248</created>
|
||||||
|
<option name="number" value="Default" />
|
||||||
|
<option name="presentableId" value="Default" />
|
||||||
|
<updated>1538745535248</updated>
|
||||||
|
</task>
|
||||||
|
<servers />
|
||||||
|
</component>
|
||||||
|
<component name="ToolWindowManager">
|
||||||
|
<frame x="-8" y="-8" width="1936" height="1056" extended-state="6" />
|
||||||
|
<editor active="true" />
|
||||||
|
<layout>
|
||||||
|
<window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.18017058" />
|
||||||
|
<window_info id="Structure" order="1" side_tool="true" weight="0.25" />
|
||||||
|
<window_info id="Favorites" order="2" side_tool="true" />
|
||||||
|
<window_info anchor="bottom" id="Message" order="0" />
|
||||||
|
<window_info anchor="bottom" id="Find" order="1" sideWeight="0.49946696" weight="0.329718" />
|
||||||
|
<window_info anchor="bottom" id="Run" order="2" sideWeight="0.4978678" visible="true" weight="0.30911064" />
|
||||||
|
<window_info anchor="bottom" id="Debug" order="3" sideWeight="0.49946696" weight="0.3991323" />
|
||||||
|
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
|
||||||
|
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
|
||||||
|
<window_info anchor="bottom" id="TODO" order="6" />
|
||||||
|
<window_info anchor="bottom" id="manage.py@youtube-channel-manager" order="7" weight="0.3290993" />
|
||||||
|
<window_info anchor="bottom" id="Docker" order="8" show_stripe_button="false" />
|
||||||
|
<window_info anchor="bottom" id="Database Changes" order="9" show_stripe_button="false" />
|
||||||
|
<window_info anchor="bottom" id="Event Log" order="10" sideWeight="0.5021322" side_tool="true" visible="true" weight="0.30911064" />
|
||||||
|
<window_info anchor="bottom" id="Version Control" order="11" />
|
||||||
|
<window_info anchor="bottom" id="Terminal" order="12" />
|
||||||
|
<window_info anchor="bottom" id="Python Console" order="13" weight="0.3290993" />
|
||||||
|
<window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" />
|
||||||
|
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
|
||||||
|
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
|
||||||
|
<window_info anchor="right" id="SciView" order="3" />
|
||||||
|
<window_info anchor="right" id="Database" order="4" />
|
||||||
|
</layout>
|
||||||
|
</component>
|
||||||
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
|
<option name="version" value="1" />
|
||||||
|
</component>
|
||||||
|
<component name="VcsContentAnnotationSettings">
|
||||||
|
<option name="myLimit" value="2678400000" />
|
||||||
|
</component>
|
||||||
|
<component name="editorHistoryManager">
|
||||||
|
<entry file="file://$PROJECT_DIR$/YtManagerApp/static/YtManagerApp/css/style.less">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state>
|
||||||
|
<caret column="18" lean-forward="true" selection-start-column="18" selection-end-column="22" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/YtManagerApp/static/YtManagerApp/import/jstree/jstree.min.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="85">
|
||||||
|
<caret line="5" column="3166" selection-start-line="5" selection-start-column="3166" selection-end-line="5" selection-end-column="3166" />
|
||||||
|
<folding>
|
||||||
|
<element signature="n#style#0;n#ins#0;n#div#0;n#!!top" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/YtManagerApp/static/YtManagerApp/css/_style.css">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="272">
|
||||||
|
<caret line="16" lean-forward="true" selection-start-line="16" selection-end-line="17" selection-end-column="26" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/YtManagerApp/static/YtManagerApp/css/style.scss">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="170">
|
||||||
|
<caret line="10" lean-forward="true" selection-start-line="10" selection-end-line="10" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/YtManagerApp/templates/YtManagerApp/controls/folder_edit_dialog.html">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="221">
|
||||||
|
<caret line="13" column="72" selection-start-line="13" selection-start-column="72" selection-end-line="13" selection-end-column="72" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/YtManagerApp/templates/YtManagerApp/main_default.html">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="357">
|
||||||
|
<caret line="26" column="4" lean-forward="true" selection-start-line="26" selection-start-column="4" selection-end-line="26" selection-end-column="4" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/YtManagerApp/views.py">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="334">
|
||||||
|
<caret line="62" lean-forward="true" selection-start-line="62" selection-end-line="62" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#35#0" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/YtManagerApp/management.py">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="504">
|
||||||
|
<caret line="42" column="11" selection-start-line="42" selection-start-column="11" selection-end-line="42" selection-end-column="11" />
|
||||||
|
<folding>
|
||||||
|
<marker date="1538766618853" expanded="true" signature="90:91" ph="..." />
|
||||||
|
<marker date="1538766618853" expanded="true" signature="642:651" ph="..." />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/YtManager/urls.py">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="272">
|
||||||
|
<caret line="19" lean-forward="true" selection-start-line="19" selection-end-line="19" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/YtManagerApp/templates/YtManagerApp/index.html">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="113">
|
||||||
|
<caret line="20" column="28" selection-start-line="20" selection-start-column="28" selection-end-line="20" selection-end-column="28" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/YtManagerApp/templates/YtManagerApp/js/subscription_tree.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="1700">
|
||||||
|
<caret line="100" column="186" selection-start-line="100" selection-start-column="186" selection-end-line="100" selection-end-column="186" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/YtManagerApp/templates/YtManagerApp/controls/subscription_edit_dialog.html">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="357">
|
||||||
|
<caret line="21" column="30" lean-forward="true" selection-start-line="21" selection-start-column="30" selection-end-line="21" selection-end-column="30" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#433#440#1#HTML" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</component>
|
||||||
|
</project>
|
31
.idea/youtube-channel-manager.iml
Normal file
31
.idea/youtube-channel-manager.iml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="FacetManager">
|
||||||
|
<facet type="django" name="Django">
|
||||||
|
<configuration>
|
||||||
|
<option name="rootFolder" value="$MODULE_DIR$" />
|
||||||
|
<option name="settingsModule" value="YtManager/settings.py" />
|
||||||
|
<option name="manageScript" value="$MODULE_DIR$/manage.py" />
|
||||||
|
<option name="environment" value="<map/>" />
|
||||||
|
<option name="doNotUseTestRunner" value="false" />
|
||||||
|
<option name="trackFilePattern" value="migrations" />
|
||||||
|
</configuration>
|
||||||
|
</facet>
|
||||||
|
</component>
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
<component name="TemplatesService">
|
||||||
|
<option name="TEMPLATE_CONFIGURATION" value="Django" />
|
||||||
|
<option name="TEMPLATE_FOLDERS">
|
||||||
|
<list>
|
||||||
|
<option value="$MODULE_DIR$/YtManagerApp/templates" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="TestRunnerService">
|
||||||
|
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
|
||||||
|
</component>
|
||||||
|
</module>
|
@ -22,5 +22,7 @@ urlpatterns = [
|
|||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
path('ajax/get_children', views.ajax_get_children, name='ajax_get_children'),
|
path('ajax/get_children', views.ajax_get_children, name='ajax_get_children'),
|
||||||
path('ajax/get_folders', views.ajax_get_folders, name='ajax_get_folders'),
|
path('ajax/get_folders', views.ajax_get_folders, name='ajax_get_folders'),
|
||||||
|
path('ajax/edit_folder', views.ajax_edit_folder, name='ajax_edit_folder'),
|
||||||
|
path('ajax/delete_folder/<int:fid>/', views.ajax_delete_folder, name='ajax_delete_folder'),
|
||||||
path(r'', views.index, name='home')
|
path(r'', views.index, name='home')
|
||||||
]
|
]
|
||||||
|
44
YtManagerApp/management.py
Normal file
44
YtManagerApp/management.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
from .models import SubscriptionFolder, Subscription, Video
|
||||||
|
|
||||||
|
|
||||||
|
class FolderManager(object):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_or_edit(fid, name, parent_id):
|
||||||
|
# Create or edit
|
||||||
|
if fid == '#':
|
||||||
|
folder = SubscriptionFolder()
|
||||||
|
else:
|
||||||
|
folder = SubscriptionFolder.objects.get(id=int(fid))
|
||||||
|
|
||||||
|
# Set attributes
|
||||||
|
folder.name = name
|
||||||
|
if parent_id == '#':
|
||||||
|
folder.parent = None
|
||||||
|
else:
|
||||||
|
folder.parent = SubscriptionFolder.objects.get(id=int(parent_id))
|
||||||
|
|
||||||
|
FolderManager.__validate(folder)
|
||||||
|
folder.save()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __validate(folder):
|
||||||
|
# Make sure folder name is unique in the parent folder
|
||||||
|
for dbFolder in SubscriptionFolder.objects.filter(parent_id=folder.parent_id):
|
||||||
|
if dbFolder.id != folder.id and dbFolder.name == folder.name:
|
||||||
|
raise ValueError('Folder name is not unique!')
|
||||||
|
|
||||||
|
# Prevent parenting loops
|
||||||
|
current = folder
|
||||||
|
visited = []
|
||||||
|
|
||||||
|
while not (current is None):
|
||||||
|
if current in visited:
|
||||||
|
raise ValueError('Parenting cycle detected!')
|
||||||
|
visited.append(current)
|
||||||
|
current = current.parent
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def delete(fid: int):
|
||||||
|
folder = SubscriptionFolder.objects.get(id=fid)
|
||||||
|
folder.delete()
|
18
YtManagerApp/migrations/0004_auto_20181005_1626.py
Normal file
18
YtManagerApp/migrations/0004_auto_20181005_1626.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 2.1.2 on 2018-10-05 13:26
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('YtManagerApp', '0003_auto_20181003_1825'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='video',
|
||||||
|
name='downloaded_path',
|
||||||
|
field=models.TextField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
@ -1,9 +1,31 @@
|
|||||||
/* Some material font helpers */
|
/* Some material font helpers */
|
||||||
|
|
||||||
.material-folder::before {
|
.material-folder::before {
|
||||||
content: "\e2c7";
|
content: "\e2c7"; }
|
||||||
}
|
|
||||||
|
|
||||||
.material-person::before {
|
.material-person::before {
|
||||||
content: "\e7fd";
|
content: "\e7fd"; }
|
||||||
}
|
|
||||||
|
/* Loading animation */
|
||||||
|
.loading-dual-ring {
|
||||||
|
display: inline-block;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px; }
|
||||||
|
|
||||||
|
.loading-dual-ring:after {
|
||||||
|
content: " ";
|
||||||
|
display: block;
|
||||||
|
width: 46px;
|
||||||
|
height: 46px;
|
||||||
|
margin: 1px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 5px solid #007bff;
|
||||||
|
border-color: #007bff transparent #007bff transparent;
|
||||||
|
animation: loading-dual-ring 1.2s linear infinite; }
|
||||||
|
|
||||||
|
@keyframes loading-dual-ring {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg); }
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg); } }
|
||||||
|
|
||||||
|
/*# sourceMappingURL=style.css.map */
|
||||||
|
7
YtManagerApp/static/YtManagerApp/css/style.css.map
Normal file
7
YtManagerApp/static/YtManagerApp/css/style.css.map
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"mappings": "AAEA,gCAAgC;AAChC,wBAAyB;EACrB,OAAO,EAAE,OAAO;;AAGpB,wBAAyB;EACrB,OAAO,EAAE,OAAO;;AAGpB,uBAAuB;AACvB,kBAAmB;EACf,OAAO,EAAE,YAAY;EACrB,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;;AAGhB,wBAAyB;EACrB,OAAO,EAAE,GAAG;EACZ,OAAO,EAAE,KAAK;EACd,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,MAAM,EAAE,GAAG;EACX,aAAa,EAAE,GAAG;EAClB,MAAM,EAAE,iBAAuB;EAC/B,YAAY,EAAE,uCAAmD;EACjE,SAAS,EAAE,sCAAsC;;AAGrD,4BAOC;EANG,EAAG;IACC,SAAS,EAAE,YAAY;EAE3B,IAAK;IACD,SAAS,EAAE,cAAc",
|
||||||
|
"sources": ["style.scss"],
|
||||||
|
"names": [],
|
||||||
|
"file": "style.css"
|
||||||
|
}
|
38
YtManagerApp/static/YtManagerApp/css/style.scss
Normal file
38
YtManagerApp/static/YtManagerApp/css/style.scss
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
$accent-color: #007bff;
|
||||||
|
|
||||||
|
/* Some material font helpers */
|
||||||
|
.material-folder::before {
|
||||||
|
content: "\e2c7";
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-person::before {
|
||||||
|
content: "\e7fd";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loading animation */
|
||||||
|
.loading-dual-ring {
|
||||||
|
display: inline-block;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-dual-ring:after {
|
||||||
|
content: " ";
|
||||||
|
display: block;
|
||||||
|
width: 46px;
|
||||||
|
height: 46px;
|
||||||
|
margin: 1px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 5px solid $accent-color;
|
||||||
|
border-color: $accent-color transparent $accent-color transparent;
|
||||||
|
animation: loading-dual-ring 1.2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes loading-dual-ring {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
@ -4592,7 +4592,7 @@
|
|||||||
if(theme_url === true) {
|
if(theme_url === true) {
|
||||||
var dir = this.settings.core.themes.dir;
|
var dir = this.settings.core.themes.dir;
|
||||||
if(!dir) { dir = $.jstree.path + '/themes'; }
|
if(!dir) { dir = $.jstree.path + '/themes'; }
|
||||||
theme_url = dir + '/' + theme_name + '/style.css';
|
theme_url = dir + '/' + theme_name + '/_style.css';
|
||||||
}
|
}
|
||||||
if(theme_url && $.inArray(theme_url, themes_loaded) === -1) {
|
if(theme_url && $.inArray(theme_url, themes_loaded) === -1) {
|
||||||
$('head').append('<'+'link rel="stylesheet" href="' + theme_url + '" type="text/css" />');
|
$('head').append('<'+'link rel="stylesheet" href="' + theme_url + '" type="text/css" />');
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
function onSelectionChanged(e, data)
|
|
||||||
{
|
|
||||||
node = data.instance.get_selected(true)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
function 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 setupTree(dataIn)
|
|
||||||
{
|
|
||||||
$("#tree-wrapper").jstree({
|
|
||||||
core : {
|
|
||||||
data : {
|
|
||||||
url : 'ajax/get_children'
|
|
||||||
},
|
|
||||||
check_callback : validateChange,
|
|
||||||
themes : {
|
|
||||||
dots : false
|
|
||||||
},
|
|
||||||
},
|
|
||||||
types : {
|
|
||||||
folder : {
|
|
||||||
icon : "material-icons material-folder"
|
|
||||||
},
|
|
||||||
sub : {
|
|
||||||
icon : "material-icons material-person",
|
|
||||||
max_depth : 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
plugins : [ "types", "wholerow", "dnd" ]
|
|
||||||
});
|
|
||||||
$("#tree-wrapper").on("changed.jstree", onSelectionChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function ()
|
|
||||||
{
|
|
||||||
setupTree();
|
|
||||||
})
|
|
@ -2,30 +2,38 @@
|
|||||||
<div class="modal-dialog" role="document">
|
<div class="modal-dialog" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<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">
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<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">
|
<div class="modal-body">
|
||||||
<form>
|
{% csrf_token %}
|
||||||
|
<input type="hidden" id="folder_edit_dialog_id" name="id" value="#">
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-sm-4" for="folder_edit_dialog_name">Name</label>
|
<label class="col-sm-3" for="folder_edit_dialog_name">Name</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-9">
|
||||||
<input type="text" class="form-control" id="folder_edit_dialog_name" placeholder="Folder name">
|
<input type="text" class="form-control" id="folder_edit_dialog_name" name="name" placeholder="Folder name">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check row">
|
<div class="form-group row">
|
||||||
<input type="checkbox" class="form-check-input" id="exampleCheck1">
|
<label class="col-sm-3" for="folder_edit_dialog_parent">Parent folder</label>
|
||||||
<label class="form-check-label" for="exampleCheck1">Check me out</label>
|
<div class="col-sm-9">
|
||||||
|
<select class="form-control" id="folder_edit_dialog_parent" name="parent">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-primary">Save changes</button>
|
<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>
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||||
</div>
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -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">×</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>
|
@ -7,7 +7,12 @@
|
|||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script src="{% static 'YtManagerApp/import/jstree/jstree.js' %}"></script>
|
<script src="{% static 'YtManagerApp/import/jstree/jstree.js' %}"></script>
|
||||||
<script src="{% static 'YtManagerApp/js/subtree.js' %}"></script>
|
<script>
|
||||||
|
{% include 'YtManagerApp/js/subscription_tree.js' %}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{% include 'YtManagerApp/controls/folder_edit_dialog.html' %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block master %}
|
{% block master %}
|
||||||
@ -17,10 +22,18 @@
|
|||||||
<button type="button" class="btn btn-secondary" >
|
<button type="button" class="btn btn-secondary" >
|
||||||
<i class="material-icons" aria-hidden="true">add</i>
|
<i class="material-icons" aria-hidden="true">add</i>
|
||||||
</button>
|
</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>
|
<i class="material-icons" aria-hidden="true">create_new_folder</i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</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>
|
||||||
|
|
||||||
<div id="tree-wrapper">
|
<div id="tree-wrapper">
|
||||||
|
174
YtManagerApp/templates/YtManagerApp/js/subscription_tree.js
Normal file
174
YtManagerApp/templates/YtManagerApp/js/subscription_tree.js
Normal 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);
|
||||||
|
});
|
@ -1,6 +1,8 @@
|
|||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.http import HttpResponse, HttpRequest, JsonResponse
|
from django.http import HttpResponse, HttpRequest, JsonResponse
|
||||||
from .models import SubscriptionFolder, Subscription
|
from .models import SubscriptionFolder, Subscription
|
||||||
|
from .management import FolderManager
|
||||||
|
|
||||||
|
|
||||||
def get_children_recurse(parent_id):
|
def get_children_recurse(parent_id):
|
||||||
children = []
|
children = []
|
||||||
@ -10,6 +12,7 @@ def get_children_recurse(parent_id):
|
|||||||
"id": "folder" + str(folder.id),
|
"id": "folder" + str(folder.id),
|
||||||
"text": folder.name,
|
"text": folder.name,
|
||||||
"type": "folder",
|
"type": "folder",
|
||||||
|
"state": {"opened": True},
|
||||||
"children": get_children_recurse(folder.id)
|
"children": get_children_recurse(folder.id)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -25,11 +28,14 @@ def get_children_recurse(parent_id):
|
|||||||
|
|
||||||
def get_folders(parent_id, path=""):
|
def get_folders(parent_id, path=""):
|
||||||
folders = []
|
folders = []
|
||||||
|
prefix = path + "/"
|
||||||
|
if len(path) == 0:
|
||||||
|
prefix = ""
|
||||||
|
|
||||||
for folder in SubscriptionFolder.objects.filter(parent_id=parent_id).order_by('name'):
|
for folder in SubscriptionFolder.objects.filter(parent_id=parent_id).order_by('name'):
|
||||||
folder_path = path + "/" + folder.name
|
folder_path = prefix + folder.name
|
||||||
folders.append({
|
folders.append({
|
||||||
"id" : "folder" + str(folder.id),
|
"id": folder.id,
|
||||||
"text": folder_path
|
"text": folder_path
|
||||||
})
|
})
|
||||||
folders.extend(get_folders(folder.id, folder_path))
|
folders.extend(get_folders(folder.id, folder_path))
|
||||||
@ -40,9 +46,26 @@ def get_folders(parent_id, path = ""):
|
|||||||
def ajax_get_children(request: HttpRequest):
|
def ajax_get_children(request: HttpRequest):
|
||||||
return JsonResponse(get_children_recurse(None), safe=False)
|
return JsonResponse(get_children_recurse(None), safe=False)
|
||||||
|
|
||||||
|
|
||||||
def ajax_get_folders(request: HttpRequest):
|
def ajax_get_folders(request: HttpRequest):
|
||||||
return JsonResponse(get_folders(None), safe=False)
|
return JsonResponse(get_folders(None), safe=False)
|
||||||
|
|
||||||
|
|
||||||
|
def ajax_edit_folder(request: HttpRequest):
|
||||||
|
if request.method == 'POST':
|
||||||
|
fid = request.POST['id']
|
||||||
|
name = request.POST['name']
|
||||||
|
parent_id = request.POST['parent']
|
||||||
|
FolderManager.create_or_edit(fid, name, parent_id)
|
||||||
|
|
||||||
|
return HttpResponse()
|
||||||
|
|
||||||
|
|
||||||
|
def ajax_delete_folder(request: HttpRequest, fid):
|
||||||
|
FolderManager.delete(fid)
|
||||||
|
return HttpResponse()
|
||||||
|
|
||||||
|
|
||||||
def index(request: HttpRequest):
|
def index(request: HttpRequest):
|
||||||
context = {}
|
context = {}
|
||||||
return render(request, 'YtManagerApp/index.html', context)
|
return render(request, 'YtManagerApp/index.html', context)
|
Loading…
Reference in New Issue
Block a user