Allow removal of folders
This commit is contained in:
parent
69b231139f
commit
277860b831
5 changed files with 119 additions and 27 deletions
|
|
@ -616,7 +616,7 @@ def deleteGcodeFile(filename, target):
|
|||
printer.unselect_file()
|
||||
|
||||
# delete it
|
||||
fileManager.remove_folder(target, filename)
|
||||
fileManager.remove_folder(target, filename, recursive=True)
|
||||
|
||||
return NO_CONTENT
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -62,6 +62,7 @@ $(function() {
|
|||
self.ignoreUpdatedFilesEvent = false;
|
||||
|
||||
self.addingFolder = ko.observable(false);
|
||||
self.activeRemovals = ko.observableArray([]);
|
||||
|
||||
self.addFolderDialog = undefined;
|
||||
self.addFolderName = ko.observable(undefined);
|
||||
|
|
@ -325,6 +326,29 @@ $(function() {
|
|||
});
|
||||
};
|
||||
|
||||
self.removeFolder = function(folder, event) {
|
||||
if (!folder) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (folder.type != "folder") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (folder.weight > 0) {
|
||||
// confirm recursive delete
|
||||
var options = {
|
||||
message: _.sprintf(gettext("You are about to delete the folder \"%(folder)s\" which still contains files and/or sub folders."), {folder: folder.name}),
|
||||
onproceed: function() {
|
||||
self._removeEntry(folder, event);
|
||||
}
|
||||
};
|
||||
showConfirmationDialog(options);
|
||||
} else {
|
||||
self._removeEntry(folder, event);
|
||||
}
|
||||
};
|
||||
|
||||
self.loadFile = function(file, printAfterLoad) {
|
||||
if (!file) {
|
||||
return;
|
||||
|
|
@ -338,29 +362,16 @@ $(function() {
|
|||
});
|
||||
};
|
||||
|
||||
self.removeFile = function(file) {
|
||||
self.removeFile = function(file, event) {
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
var index = self.listHelper.paginatedItems().indexOf(file) + 1;
|
||||
if (index >= self.listHelper.paginatedItems().length) {
|
||||
index = index - 2;
|
||||
}
|
||||
if (index < 0) {
|
||||
index = 0;
|
||||
if (file.type == "folder") {
|
||||
return;
|
||||
}
|
||||
|
||||
var filenameToFocus = undefined;
|
||||
var fileToFocus = self.listHelper.paginatedItems()[index];
|
||||
if (fileToFocus) {
|
||||
filenameToFocus = fileToFocus.name;
|
||||
}
|
||||
|
||||
OctoPrint.files.delete(file.origin, file.path)
|
||||
.done(function() {
|
||||
self.requestData(undefined, filenameToFocus, (file.parent ? file.parent.path : ""));
|
||||
})
|
||||
self._removeEntry(file, event);
|
||||
};
|
||||
|
||||
self.sliceFile = function(file) {
|
||||
|
|
@ -383,6 +394,70 @@ $(function() {
|
|||
OctoPrint.printer.refreshSd();
|
||||
};
|
||||
|
||||
self._removeEntry = function(entry, event) {
|
||||
var index = self.listHelper.paginatedItems().indexOf(entry) + 1;
|
||||
if (index >= self.listHelper.paginatedItems().length) {
|
||||
index = index - 2;
|
||||
}
|
||||
if (index < 0) {
|
||||
index = 0;
|
||||
}
|
||||
|
||||
var filenameToFocus = undefined;
|
||||
var fileToFocus = self.listHelper.paginatedItems()[index];
|
||||
if (fileToFocus) {
|
||||
filenameToFocus = fileToFocus.name;
|
||||
}
|
||||
|
||||
self.activeRemovals.push(entry.origin + ":" + entry.path);
|
||||
var finishActiveRemoval = function() {
|
||||
self.activeRemovals(_.filter(self.activeRemovals(), function(e) {
|
||||
return e != entry.origin + ":" + entry.path;
|
||||
}));
|
||||
};
|
||||
|
||||
var activateSpinner = function(){},
|
||||
finishSpinner = function(){};
|
||||
|
||||
if (event) {
|
||||
var element = $(event.currentTarget);
|
||||
if (element.length) {
|
||||
var icon = $("i.icon-trash", element);
|
||||
if (icon.length) {
|
||||
activateSpinner = function() {
|
||||
icon.removeClass("icon-trash").addClass("icon-spinner icon-spin");
|
||||
};
|
||||
finishSpinner = function() {
|
||||
icon.removeClass("icon-spinner icon-spin").addClass("icon-trash");
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
activateSpinner();
|
||||
|
||||
var deferred = $.Deferred();
|
||||
OctoPrint.files.delete(entry.origin, entry.path)
|
||||
.done(function() {
|
||||
self.requestData(undefined, filenameToFocus, (entry.parent ? entry.parent.path : ""))
|
||||
.done(function() {
|
||||
deferred.resolve();
|
||||
})
|
||||
.fail(function() {
|
||||
deferred.reject();
|
||||
});
|
||||
})
|
||||
.fail(function() {
|
||||
deferred.reject();
|
||||
});
|
||||
|
||||
return deferred.promise()
|
||||
.always(function() {
|
||||
finishActiveRemoval();
|
||||
finishSpinner();
|
||||
});
|
||||
};
|
||||
|
||||
self.downloadLink = function(data) {
|
||||
if (data["refs"] && data["refs"]["download"]) {
|
||||
return data["refs"]["download"];
|
||||
|
|
@ -425,7 +500,19 @@ $(function() {
|
|||
};
|
||||
|
||||
self.enableRemove = function(data) {
|
||||
return self.loginState.isUser() && !_.contains(self.printerState.busyFiles(), data.origin + ":" + data.name);
|
||||
if (_.contains(self.activeRemovals(), data.origin + ":" + data.path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var busy = false;
|
||||
if (data.type == "folder") {
|
||||
busy = _.any(self.printerState.busyFiles(), function(name) {
|
||||
return _.startsWith(name, data.origin + ":" + data.path + "/");
|
||||
});
|
||||
} else {
|
||||
busy = _.contains(self.printerState.busyFiles(), data.origin + ":" + data.path);
|
||||
}
|
||||
return self.loginState.isUser() && !busy;
|
||||
};
|
||||
|
||||
self.enableSelect = function(data, printAfterSelect) {
|
||||
|
|
|
|||
|
|
@ -788,6 +788,10 @@ ul.dropdown-menu li a {
|
|||
overflow: visible !important;
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.border_box {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
|
|
|
|||
|
|
@ -2,21 +2,21 @@
|
|||
<input type="text" class="input-block search-query" data-bind="value: searchQuery, valueUpdate: 'input'" placeholder="{{ _('Search...') }}">
|
||||
</form>
|
||||
<div class="gcode_files">
|
||||
<div class="entry back" data-bind="visible: currentPath() != '', click: function() { $root.navigateUp(); }" style="display: none"><i class="icon-arrow-left"></i> {{ _('Back') }}</div>
|
||||
<div class="entry back clickable" data-bind="visible: currentPath() != '', click: function() { $root.navigateUp(); }" style="display: none"><i class="icon-arrow-left"></i> {{ _('Back') }}</div>
|
||||
|
||||
<!-- ko slimScrolledForeach: filesAndFolders -->
|
||||
<div class="entry" data-bind="attr: { id: $root.getEntryId($data) }, template: { name: $root.templateFor($data), data: $data }, css: $data.type"></div>
|
||||
<!-- /ko -->
|
||||
|
||||
<script type="text/html" id="files_template_machinecode">
|
||||
<div class="title" data-bind="css: $root.getSuccessClass($data), style: { 'font-weight': $root.listHelper.isSelected($data) ? 'bold' : 'normal' }, text: name"></div>
|
||||
<div class="title clickable" data-bind="click: function() { if ($root.enableSelect($data)) { $root.loadFile($data, false); } else { return; } }, css: $root.getSuccessClass($data), style: { 'font-weight': $root.listHelper.isSelected($data) ? 'bold' : 'normal' }, text: name"></div>
|
||||
<div class="uploaded">{{ _('Uploaded') }}: <span data-bind="text: formatTimeAgo(date)"></span></div>
|
||||
<div class="size">{{ _('Size') }}: <span data-bind="text: formatSize(size)"></span></div>
|
||||
<div class="additionalInfo hide" data-bind="html: $root.getAdditionalData($data)"></div>
|
||||
<div class="btn-group action-buttons">
|
||||
<div class="btn btn-mini toggleAdditionalData" data-bind="click: function() { if ($root.enableAdditionalData($data)) { $root.toggleAdditionalData($data); } else { return; } }, css: { disabled: !$root.enableAdditionalData($data) }" title="{{ _('Additional data') }}"><i class="icon-chevron-down"></i></div>
|
||||
<a class="btn btn-mini" data-bind="attr: {href: $root.downloadLink($data)}, css: {disabled: !$root.downloadLink($data)}" title="{{ _('Download') }}"><i class="icon-download-alt"></i></a>
|
||||
<div class="btn btn-mini" data-bind="click: function() { if ($root.enableRemove($data)) { $root.removeFile($data); } else { return; } }, css: {disabled: !$root.enableRemove($data)}" title="{{ _('Remove') }}"><i class="icon-trash"></i></div>
|
||||
<div class="btn btn-mini" data-bind="click: function(data, event) { if ($root.enableRemove($data)) { $root.removeFile($data, event); } else { return; } }, css: {disabled: !$root.enableRemove($data)}" title="{{ _('Remove') }}"><i class="icon-trash"></i></div>
|
||||
<div class="btn btn-mini" data-bind="click: function() { if ($root.enableSelect($data)) { $root.loadFile($data, false); } else { return; } }, css: {disabled: !$root.enableSelect($data)}" title="{{ _('Load') }}"><i class="icon-folder-open"></i></div>
|
||||
<div class="btn btn-mini" data-bind="click: function() { if ($root.enableSelect($data)) { $root.loadFile($data, true); } else { return; } }, css: {disabled: !$root.enableSelect($data)}" title="{{ _('Load and Print') }}"><i class="icon-print"></i></div>
|
||||
</div>
|
||||
|
|
@ -28,15 +28,16 @@
|
|||
<div class="size">{{ _('Size') }}: <span data-bind="text: formatSize(size)"></span></div>
|
||||
<div class="btn-group action-buttons">
|
||||
<a class="btn btn-mini" data-bind="attr: {href: $root.downloadLink($data), css: {disabled: !$root.downloadLink($data)}}" title="{{ _('Download') }}"><i class="icon-download-alt"></i></a>
|
||||
<div class="btn btn-mini" data-bind="click: function() { if ($root.enableRemove($data)) { $root.removeFile($data); } else { return; } }, css: {disabled: !$root.enableRemove($data)}" title="{{ _('Remove') }}"><i class="icon-trash"></i></div>
|
||||
<div class="btn btn-mini" data-bind="click: function(data, event) { if ($root.enableRemove($data)) { $root.removeFile($data, event); } else { return; } }, css: {disabled: !$root.enableRemove($data)}" title="{{ _('Remove') }}"><i class="icon-trash"></i></div>
|
||||
<div class="btn btn-mini" data-bind="click: function() { if ($root.enableSlicing($data)) { $root.sliceFile($data); } else { return; } }, css: {disabled: !$root.enableSlicing($data)}" title="{{ _('Slice') }}"><i class="icon-magic"></i></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="files_template_folder">
|
||||
<div data-bind="click: $root.changeFolder">
|
||||
<div class="title" data-bind="style: { 'font-weight': $root.listHelper.isSelected($data) ? 'bold' : 'normal' }"><i class="icon-folder-open"></i> <span data-bind="text: name"></span></div>
|
||||
<div class="size">{{ _('Size') }}: <span data-bind="text: formatSize(size)"></span></div>
|
||||
<div class="title clickable" data-bind="click: $root.changeFolder, style: { 'font-weight': $root.listHelper.isSelected($data) ? 'bold' : 'normal' }"><i class="icon-folder-open"></i> <span data-bind="text: name"></span></div>
|
||||
<div class="size">{{ _('Size') }}: <span data-bind="text: formatSize(size)"></span></div>
|
||||
<div class="btn-group action-buttons">
|
||||
<div class="btn btn-mini" data-bind="click: function(data, event) { if ($root.enableRemove($data)) { $root.removeFolder($data, event); } else { return; } }, css: {disabled: !$root.enableRemove($data)}" title="{{ _('Remove') }}"><i class="icon-trash"></i></div>
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue