Changes to the WebUI to support folders

This commit is contained in:
Salandora 2015-09-07 10:34:47 +02:00
parent fb2b44f3c1
commit 5f3ee7dfda
4 changed files with 159 additions and 27 deletions

View file

@ -223,11 +223,15 @@ $(function() {
},
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
setTimeout(function() {
$(element).slimScroll({scrollBy: 0});
if (element.nodeName == "#comment")
$(element.parentElement).slimScroll({scrollBy: 0});
else
$(element).slimScroll({scrollBy: 0});
}, 10);
return ko.bindingHandlers.foreach.update(element, valueAccessor(), allBindings, viewModel, bindingContext);
}
};
ko.virtualElements.allowedBindings.slimScrolledForeach = true;
ko.bindingHandlers.qrcode = {
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {

View file

@ -54,6 +54,10 @@ $(function() {
self.uploadButton = undefined;
self.allItems = ko.observable(undefined);
self.listStyle = ko.observable("folders_files");
self.currentPath = ko.observable("");
// initialize list helper
self.listHelper = new ItemListHelper(
"gcodeFiles",
@ -78,28 +82,42 @@ $(function() {
}
},
{
"printed": function(file) {
return !(file["prints"] && file["prints"]["success"] && file["prints"]["success"] > 0);
"printed": function(data) {
return !(data["prints"] && data["prints"]["success"] && data["prints"]["success"] > 0) || (data["type"] && data["type"] == "folder");
},
"sd": function(file) {
return file["origin"] && file["origin"] == "sdcard";
"sd": function(data) {
return data["origin"] && data["origin"] == "sdcard";
},
"local": function(file) {
return !(file["origin"] && file["origin"] == "sdcard");
"local": function(data) {
return !(data["origin"] && data["origin"] == "sdcard");
},
"machinecode": function(file) {
return file["type"] && file["type"] == "machinecode";
"machinecode": function(data) {
return data["type"] && (data["type"] == "machinecode" || data["type"] == "folder");
},
"model": function(file) {
return file["type"] && file["type"] == "model";
"model": function(data) {
return data["type"] && (data["type"] == "model" || data["type"] == "folder");
},
"emptyFolder": function(data) {
return data["type"] && data["type"] != "folder" || (data["size"] && data["size"] != 0);
}
},
"name",
[],
["emptyFolder"],
[["sd", "local"], ["machinecode", "model"]],
0
);
self.foldersOnlyList = ko.dependentObservable(function() {
filter = function(data) { return data["type"] && data["type"] == "folder"; };
var items = _.filter(self.listHelper.paginatedItems(), filter);
return items;
});
self.filesOnlyList = ko.dependentObservable(function() {
filter = function(data) { return data["type"] && data["type"] != "folder"; };
var items = _.filter(self.listHelper.paginatedItems(), filter);
return items;
});
self.isLoadActionPossible = ko.computed(function() {
return self.loginState.isUser() && !self.isPrinting() && !self.isPaused() && !self.isLoading();
});
@ -142,7 +160,7 @@ $(function() {
};
self._otherRequestInProgress = false;
self.requestData = function(filenameToFocus, locationToFocus) {
self.requestData = function(filenameToFocus, locationToFocus, switchToPath) {
if (self._otherRequestInProgress) return;
self._otherRequestInProgress = true;
@ -150,8 +168,9 @@ $(function() {
url: API_BASEURL + "files",
method: "GET",
dataType: "json",
data: {"recursive": true},
success: function(response) {
self.fromResponse(response, filenameToFocus, locationToFocus);
self.fromResponse(response, filenameToFocus, locationToFocus, switchToPath);
self._otherRequestInProgress = false;
},
error: function() {
@ -160,13 +179,32 @@ $(function() {
});
};
self.fromResponse = function(response, filenameToFocus, locationToFocus) {
self.fromResponse = function(response, filenameToFocus, locationToFocus, switchToPath) {
var files = response.files;
_.each(files, function(element, index, list) {
recursiveCheck = function(element, index, list) {
if (!element.hasOwnProperty("parent")) element.parent = { children: list, parent: undefined };
if (!element.hasOwnProperty("size")) element.size = undefined;
if (!element.hasOwnProperty("date")) element.date = undefined;
});
self.listHelper.updateItems(files);
if (element.type == "folder")
{
for (var i = 0; i < element.children.length; i++) {
element.children[i].parent = element;
recursiveCheck(element.children[i], i, element.children);
}
}
};
_.each(files, recursiveCheck);
self.allItems(files);
self.currentPath("");
self.listHelper.addFilter("emptyFolder");
if (!switchToPath) {
self.listHelper.updateItems(files);
}
else {
self.changeFolderByPath(switchToPath);
}
if (filenameToFocus) {
// got a file to scroll to
@ -191,6 +229,52 @@ $(function() {
self.highlightFilename(self.printerState.filename());
};
self.changeFolder = function(data) {
self.currentPath(self.pathByElement(data));
self.listHelper.updateItems(data.children);
};
self.changeFolderByPath = function(path) {
var element = self.elementByPath(path, { children: self.allItems() });
if (element) {
self.currentPath(path);
self.listHelper.updateItems(element.children);
}
else{
self.currentPath("");
self.listHelper.updateItems(self.allItems());
}
}
self.pathByElement = function(element) {
if (!element || element.parent == undefined)
return "";
recursivePath = function(element, path) {
if (element.parent !== undefined)
return recursivePath(element.parent, element.name + "/" + path);
return path;
};
return recursivePath(element.parent, element.name);
};
self.elementByPath = function(path, startElement) {
recursiveSearch = function(path, element) {
if (path.length == 0)
return element;
var name = path.shift();
for(var i = 0; i< startElement.children.length; i++) {
if (name == startElement.children[i].name) {
return recursivePath(path, startElement.children[i]);
}
}
return undefined;
};
return recursiveSearch(path.split("/"), startElement);
};
self.loadFile = function(file, printAfterLoad) {
if (!file || !file.refs || !file.refs.hasOwnProperty("resource")) return;
@ -206,11 +290,22 @@ $(function() {
self.removeFile = function(file) {
if (!file || !file.refs || !file.refs.hasOwnProperty("resource")) return;
var index = self.listHelper.paginatedItems().indexOf(file) + 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;
$.ajax({
url: file.refs.resource,
type: "DELETE",
success: function() {
self.requestData();
self.requestData(undefined, filenameToFocus, self.pathByElement(file.parent));
}
});
};
@ -352,7 +447,7 @@ $(function() {
};
self.onDataUpdaterReconnect = function() {
self.requestData();
self.requestData(undefined, undefined, self.currentPath());
};
self.onUserLoggedIn = function(user) {
@ -397,7 +492,7 @@ $(function() {
filename = data.result.files.local.name;
location = "local";
}
self.requestData(filename, location);
self.requestData(filename, location, self.currentPath());
if (_.endsWith(filename.toLowerCase(), ".stl")) {
self.slicing.show(location, filename);
@ -442,6 +537,8 @@ $(function() {
done: gcode_upload_done,
fail: gcode_upload_fail,
progressall: gcode_upload_progress
}).bind('fileuploadsubmit', function(e, data) {
data.formData = { path: self.currentPath() };
});
}
@ -464,6 +561,8 @@ $(function() {
done: gcode_upload_done,
fail: gcode_upload_fail,
progressall: gcode_upload_progress
}).bind('fileuploadsubmit', function(e, data) {
data.formData = { path: self.currentPath() };
});
}
@ -585,20 +684,20 @@ $(function() {
self.onEventUpdatedFiles = function(payload) {
if (payload.type == "gcode") {
self.requestData();
self.requestData(undefined, undefined, self.currentPath());
}
};
self.onEventSlicingDone = function(payload) {
self.requestData();
self.requestData(undefined, undefined, self.currentPath());
};
self.onEventMetadataAnalysisFinished = function(payload) {
self.requestData();
self.requestData(undefined, undefined, self.currentPath());
};
self.onEventMetadataStatisticsUpdated = function(payload) {
self.requestData();
self.requestData(undefined, undefined, self.currentPath());
};
}

View file

@ -1,8 +1,32 @@
<form class="form-search" data-bind="submit: performSearch">
<input type="text" class="input-block search-query" data-bind="value: searchQuery, valueUpdate: 'input'" placeholder="{{ _('Search...') }}">
</form>
<div class="gcode_files" data-bind="slimScrolledForeach: listHelper.paginatedItems">
<div class="gcode_files">
<!-- ko if: currentPath() != "" -->
<div class="entry" data-bind="click: function() { var path = $root.currentPath().split('/'); path.shift(); $root.changeFolderByPath(path.join('/')); }"><i class="icon-arrow-left"></i> {{ _('Back') }}</div>
<!-- /ko -->
<!-- ko if: listStyle() == 'folders_files' -->
<!-- ko slimScrolledForeach: foldersOnlyList -->
<div class="entry" data-bind="attr: { id: $root.getEntryId($data) }, template: { name: $root.templateFor($data), data: $data }"></div>
<!-- /ko -->
<!-- ko slimScrolledForeach: filesOnlyList -->
<div class="entry" data-bind="attr: { id: $root.getEntryId($data) }, template: { name: $root.templateFor($data), data: $data }"></div>
<!-- /ko -->
<!-- /ko -->
<!-- ko if: listStyle() == 'files_folders' -->
<!-- ko slimScrolledForeach: filesOnlyList -->
<div class="entry" data-bind="attr: { id: $root.getEntryId($data) }, template: { name: $root.templateFor($data), data: $data }"></div>
<!-- /ko -->
<!-- ko slimScrolledForeach: foldersOnlyList -->
<div class="entry" data-bind="attr: { id: $root.getEntryId($data) }, template: { name: $root.templateFor($data), data: $data }"></div>
<!-- /ko -->
<!-- /ko -->
<!-- ko if: listStyle() == 'mixed' -->
<!-- ko slimScrolledForeach: listHelper.paginatedItems -->
<div class="entry" data-bind="attr: { id: $root.getEntryId($data) }, template: { name: $root.templateFor($data), data: $data }"></div>
<!-- /ko -->
<!-- /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>
@ -30,7 +54,8 @@
</script>
<script type="text/html" id="files_template_folder">
<div class="title" data-bind="text: name"></div>
<div class="title" data-bind="click: $root.changeFolder"><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>
</script>
</div>
<div class="text-right muted" data-bind="attr: {title: diskusageString}, css: {'text-error': diskusageCritical}, style: {'font-weight': diskusageCritical() || diskusageWarning() ? 'bold' : 'normal'}">

View file

@ -3,6 +3,10 @@
<span class="icon-wrench"></span>
</a>
<ul class="dropdown-menu">
<li><a href="#" data-bind="click: function() { $root.listStyle('folders_files'); }"><i class="icon-ok" data-bind="style: {visibility: listStyle() == 'folders_files' ? 'visible' : 'hidden'}"></i> {{ _('Sort by Folders, Files') }}</a></li>
<li><a href="#" data-bind="click: function() { $root.listStyle('files_folders'); }"><i class="icon-ok" data-bind="style: {visibility: listStyle() == 'files_folders' ? 'visible' : 'hidden'}"></i> {{ _('Sort by Files, Folders') }}</a></li>
<li><a href="#" data-bind="click: function() { $root.listStyle('mixed'); }"><i class="icon-ok" data-bind="style: {visibility: listStyle() == 'mixed' ? 'visible' : 'hidden'}"></i> {{ _('Mixed') }}</a></li>
<li class="divider"></li>
<li><a href="#" data-bind="click: function() { $root.listHelper.changeSorting('name'); }"><i class="icon-ok" data-bind="style: {visibility: listHelper.currentSorting() == 'name' ? 'visible' : 'hidden'}"></i> {{ _('Sort by name') }} ({{ _('ascending') }})</a></li>
<li><a href="#" data-bind="click: function() { $root.listHelper.changeSorting('upload'); }"><i class="icon-ok" data-bind="style: {visibility: listHelper.currentSorting() == 'upload' ? 'visible' : 'hidden'}"></i> {{ _('Sort by upload date') }} ({{ _('descending') }})</a></li>
<li><a href="#" data-bind="click: function() { $root.listHelper.changeSorting('size'); }"><i class="icon-ok" data-bind="style: {visibility: listHelper.currentSorting() == 'size' ? 'visible' : 'hidden'}"></i> {{ _('Sort by file size') }} ({{ _('descending') }})</a></li>